Can I write a for loop that iterates over both collections and arrays?
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
Is there a possibility to check if an object is either an array or a collection with one clause? What I am trying to achieve:
Assuming arrays implement Iterable, and assuming the Object foo
could be either an array or a collection, I'd like to use a code snippet like this:
if (foo instanceof Iterable) {
for (Object f : (Iterable) foo) {
// do something with f
}
}
Unfortunately, an array cannot be cast to Iterable. Nor does it implement Collection. Are there any other possibilities to handle both in one loop like the above? Instead of -- of course -- using an if-else if-clause and two loops (which wouldn't be nice).
Edit: In response to these answers. I am aware of the isArray() method but in this case the casting in
...
for (Object f : (Iterable) foo) {
...
will fail. That'd a pity and a code redundancy since I would have to use two loops although a foreach-loop works both with Collections and Arrays.
java arrays collections
add a comment |
Is there a possibility to check if an object is either an array or a collection with one clause? What I am trying to achieve:
Assuming arrays implement Iterable, and assuming the Object foo
could be either an array or a collection, I'd like to use a code snippet like this:
if (foo instanceof Iterable) {
for (Object f : (Iterable) foo) {
// do something with f
}
}
Unfortunately, an array cannot be cast to Iterable. Nor does it implement Collection. Are there any other possibilities to handle both in one loop like the above? Instead of -- of course -- using an if-else if-clause and two loops (which wouldn't be nice).
Edit: In response to these answers. I am aware of the isArray() method but in this case the casting in
...
for (Object f : (Iterable) foo) {
...
will fail. That'd a pity and a code redundancy since I would have to use two loops although a foreach-loop works both with Collections and Arrays.
java arrays collections
The way I see it,foo
must be declared asObject
. So you have to cast anyway. Are you trying to cast just once?
– ernest_k
5 hours ago
The foreach-loop won't work if I cast it to Object -- you cannot iterate through objects.
– Pawel Os.
4 hours ago
That's exactly the point I'm trying to make.
– ernest_k
4 hours ago
6
It's a good idea to avoid a design that leads to this in the first place. Even if you had a common interface for this to work with just one for-each loop, you'd still have many type casts. Your code wouldn't be type-safe (Object
? rawIterable
?)
– ernest_k
4 hours ago
I've changed the question title to better match the body.
– John Kugelman
15 mins ago
add a comment |
Is there a possibility to check if an object is either an array or a collection with one clause? What I am trying to achieve:
Assuming arrays implement Iterable, and assuming the Object foo
could be either an array or a collection, I'd like to use a code snippet like this:
if (foo instanceof Iterable) {
for (Object f : (Iterable) foo) {
// do something with f
}
}
Unfortunately, an array cannot be cast to Iterable. Nor does it implement Collection. Are there any other possibilities to handle both in one loop like the above? Instead of -- of course -- using an if-else if-clause and two loops (which wouldn't be nice).
Edit: In response to these answers. I am aware of the isArray() method but in this case the casting in
...
for (Object f : (Iterable) foo) {
...
will fail. That'd a pity and a code redundancy since I would have to use two loops although a foreach-loop works both with Collections and Arrays.
java arrays collections
Is there a possibility to check if an object is either an array or a collection with one clause? What I am trying to achieve:
Assuming arrays implement Iterable, and assuming the Object foo
could be either an array or a collection, I'd like to use a code snippet like this:
if (foo instanceof Iterable) {
for (Object f : (Iterable) foo) {
// do something with f
}
}
Unfortunately, an array cannot be cast to Iterable. Nor does it implement Collection. Are there any other possibilities to handle both in one loop like the above? Instead of -- of course -- using an if-else if-clause and two loops (which wouldn't be nice).
Edit: In response to these answers. I am aware of the isArray() method but in this case the casting in
...
for (Object f : (Iterable) foo) {
...
will fail. That'd a pity and a code redundancy since I would have to use two loops although a foreach-loop works both with Collections and Arrays.
java arrays collections
java arrays collections
edited 16 mins ago
John Kugelman
248k54406460
248k54406460
asked 5 hours ago
Pawel Os.Pawel Os.
137115
137115
The way I see it,foo
must be declared asObject
. So you have to cast anyway. Are you trying to cast just once?
– ernest_k
5 hours ago
The foreach-loop won't work if I cast it to Object -- you cannot iterate through objects.
– Pawel Os.
4 hours ago
That's exactly the point I'm trying to make.
– ernest_k
4 hours ago
6
It's a good idea to avoid a design that leads to this in the first place. Even if you had a common interface for this to work with just one for-each loop, you'd still have many type casts. Your code wouldn't be type-safe (Object
? rawIterable
?)
– ernest_k
4 hours ago
I've changed the question title to better match the body.
– John Kugelman
15 mins ago
add a comment |
The way I see it,foo
must be declared asObject
. So you have to cast anyway. Are you trying to cast just once?
– ernest_k
5 hours ago
The foreach-loop won't work if I cast it to Object -- you cannot iterate through objects.
– Pawel Os.
4 hours ago
That's exactly the point I'm trying to make.
– ernest_k
4 hours ago
6
It's a good idea to avoid a design that leads to this in the first place. Even if you had a common interface for this to work with just one for-each loop, you'd still have many type casts. Your code wouldn't be type-safe (Object
? rawIterable
?)
– ernest_k
4 hours ago
I've changed the question title to better match the body.
– John Kugelman
15 mins ago
The way I see it,
foo
must be declared as Object
. So you have to cast anyway. Are you trying to cast just once?– ernest_k
5 hours ago
The way I see it,
foo
must be declared as Object
. So you have to cast anyway. Are you trying to cast just once?– ernest_k
5 hours ago
The foreach-loop won't work if I cast it to Object -- you cannot iterate through objects.
– Pawel Os.
4 hours ago
The foreach-loop won't work if I cast it to Object -- you cannot iterate through objects.
– Pawel Os.
4 hours ago
That's exactly the point I'm trying to make.
– ernest_k
4 hours ago
That's exactly the point I'm trying to make.
– ernest_k
4 hours ago
6
6
It's a good idea to avoid a design that leads to this in the first place. Even if you had a common interface for this to work with just one for-each loop, you'd still have many type casts. Your code wouldn't be type-safe (
Object
? raw Iterable
?)– ernest_k
4 hours ago
It's a good idea to avoid a design that leads to this in the first place. Even if you had a common interface for this to work with just one for-each loop, you'd still have many type casts. Your code wouldn't be type-safe (
Object
? raw Iterable
?)– ernest_k
4 hours ago
I've changed the question title to better match the body.
– John Kugelman
15 mins ago
I've changed the question title to better match the body.
– John Kugelman
15 mins ago
add a comment |
6 Answers
6
active
oldest
votes
Class#isAssignableFrom
may come in handy.
Class<?> fooClass = foo.getClass();
boolean isArrayOrCollection = Collection.class.isAssignableFrom(fooClass) ||
Object.class.isAssignableFrom(fooClass);
I reasonably assume you won't test it on primitive arrays since you have collections which work only with the wrapper classes.
I guess you can safely replace Object.class.isAssignableFrom(fooClass)
with fooClass.isArray()
boolean isArrayOrCollection = Collection.class.isAssignableFrom(fooClass) ||
fooClass.isArray();
and it would also work for a primitive array class.
I've run a small "test"
class Test {
public static void main(String args) {
Predicate<Class<?>> p = c -> Collection.class.isAssignableFrom(c) ||
c.isArray();
System.out.println(p.test(new int[0].getClass()));
System.out.println(p.test(new Integer[0].getClass()));
System.out.println(p.test(Collections.emptyList().getClass()));
System.out.println(p.test(Collections.emptySet().getClass()));
System.out.println(p.test(Collections.emptyMap().getClass()));
}
}
which results in
true
true
true
true
false
Regarding a generic loop that would run over both arrays and collections:
You simply can't write an accurate construction to handle this: Collection
(or Iterable
) and Object
have little in common (Object
as a common parent and its methods are not enough).
I think it's sensible to build own abstraction which would treat collections and arrays in the same manner.
Whereas this seems good practical advice for the OP, it does not directly respond to the actual question, which inquires about a common supertype of collections and arrays.
– John Bollinger
1 hour ago
How does this help as far as writing a singlefor
loop?
– John Kugelman
17 mins ago
add a comment |
You can check if object is array by using isArray()
method from Class
if (foo != null && (foo.getClass().isArray() || foo instanceof Collection<?>)){
}
you can just check iffoo instanceof Collection<?>
. Shorter and more clear in my opinion. No nee to useCollection.class.isAssignableFrom
. I've added partial answer because at first you didn't includeisArray()
method in your answer :)
– Mershel
4 hours ago
Though, I still believe thatCollection.class.isAssignableFrom(fooClass)
is more flexible thanfoo instanceof Collection
becauseCollection.class
could be any class at runtime (a dynamically obtained one, I mean)
– Andrew Tobilko
3 hours ago
Wouldn't that throw NPE when we would passint i = null
? I think that there will be no difference betweenCollection.class.isAssignableFrom(fooClass)
andfoo instanceof Collection<?>
, that is just up to what you prefer and what is more readable for you ;)
– Mershel
3 hours ago
add a comment |
Arrays extend Object:
https://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html
AbstractCollections also extend Object:
https://docs.oracle.com/javase/8/docs/api/java/util/AbstractCollection.html
So yes there is a common superclass, but unfortunately this isn't really going to help you.
I would suggest your best bet is to use:
List<> someList = Arrays.asList(sourceArray)
This will convert your array into a collection that implements Iterable. You will of course need to work out if the initial object is an Array or a Collection in advance and only call the above if it is an array, here are some options for doing that:
boolean isArray = myArray.getClass().isArray();
boolean isCollection = Collection.class.isAssignableFrom(myList.getClass());
3
Arrays.asList()
will sadly not work with primitive arrays
– Lino
4 hours ago
1
Agreed, but I'm making the assumption here that the OP is not using primitive arrays. If they are they could do something likeInteger boxedInts = IntStream.of(ints).boxed().toArray(Integer::new);
(Assuming they aren't using a byte array, in which case it gets more complex)
– Ardesco
4 hours ago
add a comment |
You could write a helper method for this:
@SuppressWarnings("unchecked")
public static <E> void forEach(Object arrayOrIterable, Consumer<? super E> action) {
Objects.requireNonNull(arrayOrIterable);
if (arrayOrIterable instanceof Iterable) {
for (Object o : (Iterable<?>) arrayOrIterable) {
action.accept((E) o);
}
} else if (arrayOrIterable.getClass().isArray()) {
int length = Array.getLength(arrayOrIterable);
for (int i = 0; i < length; i++) {
action.accept((E) Array.get(arrayOrIterable, i));
}
} else {
throw new IllegalArgumentException("not an array nor iterable: " + arrayOrIterable.getClass());
}
}
The second branch makes use of the java.reflect.Array
class which provides helper methods (may be slow), to get the length
of an array and the element at a given index.
You may call it like this:
int ints = {1, 2, 3, 4};
forEach(ints, (Integer i) -> System.out.println(i));
List<Integer> ints = Arrays.asList(1, 2, 3, 4);
forEach(ints, (Integer i) -> System.out.println(i));
Due to the nature of generics, this method may throw a ClassCastException
, e.g. this call:
int ints = {1, 2, 3, 4};
forEach(ints, (String s) -> System.out.println(s));
Would result in:
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
I wouldn't dare to name the parameterarrayOrIterable
since it's anObject
and it might be anything
– Andrew Tobilko
4 hours ago
1
@AndrewTobilko Well this method only works with an array or an iterable, and will throw an exception for every otherObject
, so this should help as documentation that really one of those two types is expected
– Lino
4 hours ago
oh, I get you. It's a matter of personal preference/style, I guess.
– Andrew Tobilko
4 hours ago
2
@AndrewTobilko It really is something that is purely opinion based, best would be of course an extensive java-doc stating what can be passed into this method, what exceptions may be thrown etc.
– Lino
4 hours ago
add a comment |
Depending on what you are trying to do, you might want to implement two similar methods:
public <T> void iterateOver(List<T> list) {
// do whatever you want to do with your list
}
public <T> void iterateOver(T array) {
this.iterateOver(Arrays.asList(array));
}
Or maybe even have an interface for this:
interface ExtendedIterableConsumer<T> {
public void iterateOver(List<T> list);
public default void iterateOver(T array) {
this.iterateOver(Arrays.asList(array));
}
I am not sure if that helps you, because you seem to already have the object in question in a variable somewhere. But if you can address that problem one level higher, it might be useful.
1
+1 because it's already too late to try to solve the problem in the method. The architecture should probably be slightly changed.
– Eric Duminil
1 hour ago
add a comment |
The other answers are all trying hard to answer the title question, but your real question is in the body. The answer is: No, there's no way to write a single for
loop that iterates over both collections and arrays.
You could jump through a bunch of hoops to turn the arrays into lists, but you'll almost certainly end up with a bigger mess than if you just wrote two (or more) loops. Calling getClass().isArray()
tells you what you have but you still can't work with it without some sort of cast. Arrays.asList()
doesn't work for arrays of primitives.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55588278%2fcan-i-write-a-for-loop-that-iterates-over-both-collections-and-arrays%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
6 Answers
6
active
oldest
votes
6 Answers
6
active
oldest
votes
active
oldest
votes
active
oldest
votes
Class#isAssignableFrom
may come in handy.
Class<?> fooClass = foo.getClass();
boolean isArrayOrCollection = Collection.class.isAssignableFrom(fooClass) ||
Object.class.isAssignableFrom(fooClass);
I reasonably assume you won't test it on primitive arrays since you have collections which work only with the wrapper classes.
I guess you can safely replace Object.class.isAssignableFrom(fooClass)
with fooClass.isArray()
boolean isArrayOrCollection = Collection.class.isAssignableFrom(fooClass) ||
fooClass.isArray();
and it would also work for a primitive array class.
I've run a small "test"
class Test {
public static void main(String args) {
Predicate<Class<?>> p = c -> Collection.class.isAssignableFrom(c) ||
c.isArray();
System.out.println(p.test(new int[0].getClass()));
System.out.println(p.test(new Integer[0].getClass()));
System.out.println(p.test(Collections.emptyList().getClass()));
System.out.println(p.test(Collections.emptySet().getClass()));
System.out.println(p.test(Collections.emptyMap().getClass()));
}
}
which results in
true
true
true
true
false
Regarding a generic loop that would run over both arrays and collections:
You simply can't write an accurate construction to handle this: Collection
(or Iterable
) and Object
have little in common (Object
as a common parent and its methods are not enough).
I think it's sensible to build own abstraction which would treat collections and arrays in the same manner.
Whereas this seems good practical advice for the OP, it does not directly respond to the actual question, which inquires about a common supertype of collections and arrays.
– John Bollinger
1 hour ago
How does this help as far as writing a singlefor
loop?
– John Kugelman
17 mins ago
add a comment |
Class#isAssignableFrom
may come in handy.
Class<?> fooClass = foo.getClass();
boolean isArrayOrCollection = Collection.class.isAssignableFrom(fooClass) ||
Object.class.isAssignableFrom(fooClass);
I reasonably assume you won't test it on primitive arrays since you have collections which work only with the wrapper classes.
I guess you can safely replace Object.class.isAssignableFrom(fooClass)
with fooClass.isArray()
boolean isArrayOrCollection = Collection.class.isAssignableFrom(fooClass) ||
fooClass.isArray();
and it would also work for a primitive array class.
I've run a small "test"
class Test {
public static void main(String args) {
Predicate<Class<?>> p = c -> Collection.class.isAssignableFrom(c) ||
c.isArray();
System.out.println(p.test(new int[0].getClass()));
System.out.println(p.test(new Integer[0].getClass()));
System.out.println(p.test(Collections.emptyList().getClass()));
System.out.println(p.test(Collections.emptySet().getClass()));
System.out.println(p.test(Collections.emptyMap().getClass()));
}
}
which results in
true
true
true
true
false
Regarding a generic loop that would run over both arrays and collections:
You simply can't write an accurate construction to handle this: Collection
(or Iterable
) and Object
have little in common (Object
as a common parent and its methods are not enough).
I think it's sensible to build own abstraction which would treat collections and arrays in the same manner.
Whereas this seems good practical advice for the OP, it does not directly respond to the actual question, which inquires about a common supertype of collections and arrays.
– John Bollinger
1 hour ago
How does this help as far as writing a singlefor
loop?
– John Kugelman
17 mins ago
add a comment |
Class#isAssignableFrom
may come in handy.
Class<?> fooClass = foo.getClass();
boolean isArrayOrCollection = Collection.class.isAssignableFrom(fooClass) ||
Object.class.isAssignableFrom(fooClass);
I reasonably assume you won't test it on primitive arrays since you have collections which work only with the wrapper classes.
I guess you can safely replace Object.class.isAssignableFrom(fooClass)
with fooClass.isArray()
boolean isArrayOrCollection = Collection.class.isAssignableFrom(fooClass) ||
fooClass.isArray();
and it would also work for a primitive array class.
I've run a small "test"
class Test {
public static void main(String args) {
Predicate<Class<?>> p = c -> Collection.class.isAssignableFrom(c) ||
c.isArray();
System.out.println(p.test(new int[0].getClass()));
System.out.println(p.test(new Integer[0].getClass()));
System.out.println(p.test(Collections.emptyList().getClass()));
System.out.println(p.test(Collections.emptySet().getClass()));
System.out.println(p.test(Collections.emptyMap().getClass()));
}
}
which results in
true
true
true
true
false
Regarding a generic loop that would run over both arrays and collections:
You simply can't write an accurate construction to handle this: Collection
(or Iterable
) and Object
have little in common (Object
as a common parent and its methods are not enough).
I think it's sensible to build own abstraction which would treat collections and arrays in the same manner.
Class#isAssignableFrom
may come in handy.
Class<?> fooClass = foo.getClass();
boolean isArrayOrCollection = Collection.class.isAssignableFrom(fooClass) ||
Object.class.isAssignableFrom(fooClass);
I reasonably assume you won't test it on primitive arrays since you have collections which work only with the wrapper classes.
I guess you can safely replace Object.class.isAssignableFrom(fooClass)
with fooClass.isArray()
boolean isArrayOrCollection = Collection.class.isAssignableFrom(fooClass) ||
fooClass.isArray();
and it would also work for a primitive array class.
I've run a small "test"
class Test {
public static void main(String args) {
Predicate<Class<?>> p = c -> Collection.class.isAssignableFrom(c) ||
c.isArray();
System.out.println(p.test(new int[0].getClass()));
System.out.println(p.test(new Integer[0].getClass()));
System.out.println(p.test(Collections.emptyList().getClass()));
System.out.println(p.test(Collections.emptySet().getClass()));
System.out.println(p.test(Collections.emptyMap().getClass()));
}
}
which results in
true
true
true
true
false
Regarding a generic loop that would run over both arrays and collections:
You simply can't write an accurate construction to handle this: Collection
(or Iterable
) and Object
have little in common (Object
as a common parent and its methods are not enough).
I think it's sensible to build own abstraction which would treat collections and arrays in the same manner.
edited 4 mins ago
answered 5 hours ago
Andrew TobilkoAndrew Tobilko
28.5k104590
28.5k104590
Whereas this seems good practical advice for the OP, it does not directly respond to the actual question, which inquires about a common supertype of collections and arrays.
– John Bollinger
1 hour ago
How does this help as far as writing a singlefor
loop?
– John Kugelman
17 mins ago
add a comment |
Whereas this seems good practical advice for the OP, it does not directly respond to the actual question, which inquires about a common supertype of collections and arrays.
– John Bollinger
1 hour ago
How does this help as far as writing a singlefor
loop?
– John Kugelman
17 mins ago
Whereas this seems good practical advice for the OP, it does not directly respond to the actual question, which inquires about a common supertype of collections and arrays.
– John Bollinger
1 hour ago
Whereas this seems good practical advice for the OP, it does not directly respond to the actual question, which inquires about a common supertype of collections and arrays.
– John Bollinger
1 hour ago
How does this help as far as writing a single
for
loop?– John Kugelman
17 mins ago
How does this help as far as writing a single
for
loop?– John Kugelman
17 mins ago
add a comment |
You can check if object is array by using isArray()
method from Class
if (foo != null && (foo.getClass().isArray() || foo instanceof Collection<?>)){
}
you can just check iffoo instanceof Collection<?>
. Shorter and more clear in my opinion. No nee to useCollection.class.isAssignableFrom
. I've added partial answer because at first you didn't includeisArray()
method in your answer :)
– Mershel
4 hours ago
Though, I still believe thatCollection.class.isAssignableFrom(fooClass)
is more flexible thanfoo instanceof Collection
becauseCollection.class
could be any class at runtime (a dynamically obtained one, I mean)
– Andrew Tobilko
3 hours ago
Wouldn't that throw NPE when we would passint i = null
? I think that there will be no difference betweenCollection.class.isAssignableFrom(fooClass)
andfoo instanceof Collection<?>
, that is just up to what you prefer and what is more readable for you ;)
– Mershel
3 hours ago
add a comment |
You can check if object is array by using isArray()
method from Class
if (foo != null && (foo.getClass().isArray() || foo instanceof Collection<?>)){
}
you can just check iffoo instanceof Collection<?>
. Shorter and more clear in my opinion. No nee to useCollection.class.isAssignableFrom
. I've added partial answer because at first you didn't includeisArray()
method in your answer :)
– Mershel
4 hours ago
Though, I still believe thatCollection.class.isAssignableFrom(fooClass)
is more flexible thanfoo instanceof Collection
becauseCollection.class
could be any class at runtime (a dynamically obtained one, I mean)
– Andrew Tobilko
3 hours ago
Wouldn't that throw NPE when we would passint i = null
? I think that there will be no difference betweenCollection.class.isAssignableFrom(fooClass)
andfoo instanceof Collection<?>
, that is just up to what you prefer and what is more readable for you ;)
– Mershel
3 hours ago
add a comment |
You can check if object is array by using isArray()
method from Class
if (foo != null && (foo.getClass().isArray() || foo instanceof Collection<?>)){
}
You can check if object is array by using isArray()
method from Class
if (foo != null && (foo.getClass().isArray() || foo instanceof Collection<?>)){
}
edited 3 hours ago
answered 5 hours ago
MershelMershel
270211
270211
you can just check iffoo instanceof Collection<?>
. Shorter and more clear in my opinion. No nee to useCollection.class.isAssignableFrom
. I've added partial answer because at first you didn't includeisArray()
method in your answer :)
– Mershel
4 hours ago
Though, I still believe thatCollection.class.isAssignableFrom(fooClass)
is more flexible thanfoo instanceof Collection
becauseCollection.class
could be any class at runtime (a dynamically obtained one, I mean)
– Andrew Tobilko
3 hours ago
Wouldn't that throw NPE when we would passint i = null
? I think that there will be no difference betweenCollection.class.isAssignableFrom(fooClass)
andfoo instanceof Collection<?>
, that is just up to what you prefer and what is more readable for you ;)
– Mershel
3 hours ago
add a comment |
you can just check iffoo instanceof Collection<?>
. Shorter and more clear in my opinion. No nee to useCollection.class.isAssignableFrom
. I've added partial answer because at first you didn't includeisArray()
method in your answer :)
– Mershel
4 hours ago
Though, I still believe thatCollection.class.isAssignableFrom(fooClass)
is more flexible thanfoo instanceof Collection
becauseCollection.class
could be any class at runtime (a dynamically obtained one, I mean)
– Andrew Tobilko
3 hours ago
Wouldn't that throw NPE when we would passint i = null
? I think that there will be no difference betweenCollection.class.isAssignableFrom(fooClass)
andfoo instanceof Collection<?>
, that is just up to what you prefer and what is more readable for you ;)
– Mershel
3 hours ago
you can just check if
foo instanceof Collection<?>
. Shorter and more clear in my opinion. No nee to use Collection.class.isAssignableFrom
. I've added partial answer because at first you didn't include isArray()
method in your answer :)– Mershel
4 hours ago
you can just check if
foo instanceof Collection<?>
. Shorter and more clear in my opinion. No nee to use Collection.class.isAssignableFrom
. I've added partial answer because at first you didn't include isArray()
method in your answer :)– Mershel
4 hours ago
Though, I still believe that
Collection.class.isAssignableFrom(fooClass)
is more flexible than foo instanceof Collection
because Collection.class
could be any class at runtime (a dynamically obtained one, I mean)– Andrew Tobilko
3 hours ago
Though, I still believe that
Collection.class.isAssignableFrom(fooClass)
is more flexible than foo instanceof Collection
because Collection.class
could be any class at runtime (a dynamically obtained one, I mean)– Andrew Tobilko
3 hours ago
Wouldn't that throw NPE when we would pass
int i = null
? I think that there will be no difference between Collection.class.isAssignableFrom(fooClass)
and foo instanceof Collection<?>
, that is just up to what you prefer and what is more readable for you ;)– Mershel
3 hours ago
Wouldn't that throw NPE when we would pass
int i = null
? I think that there will be no difference between Collection.class.isAssignableFrom(fooClass)
and foo instanceof Collection<?>
, that is just up to what you prefer and what is more readable for you ;)– Mershel
3 hours ago
add a comment |
Arrays extend Object:
https://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html
AbstractCollections also extend Object:
https://docs.oracle.com/javase/8/docs/api/java/util/AbstractCollection.html
So yes there is a common superclass, but unfortunately this isn't really going to help you.
I would suggest your best bet is to use:
List<> someList = Arrays.asList(sourceArray)
This will convert your array into a collection that implements Iterable. You will of course need to work out if the initial object is an Array or a Collection in advance and only call the above if it is an array, here are some options for doing that:
boolean isArray = myArray.getClass().isArray();
boolean isCollection = Collection.class.isAssignableFrom(myList.getClass());
3
Arrays.asList()
will sadly not work with primitive arrays
– Lino
4 hours ago
1
Agreed, but I'm making the assumption here that the OP is not using primitive arrays. If they are they could do something likeInteger boxedInts = IntStream.of(ints).boxed().toArray(Integer::new);
(Assuming they aren't using a byte array, in which case it gets more complex)
– Ardesco
4 hours ago
add a comment |
Arrays extend Object:
https://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html
AbstractCollections also extend Object:
https://docs.oracle.com/javase/8/docs/api/java/util/AbstractCollection.html
So yes there is a common superclass, but unfortunately this isn't really going to help you.
I would suggest your best bet is to use:
List<> someList = Arrays.asList(sourceArray)
This will convert your array into a collection that implements Iterable. You will of course need to work out if the initial object is an Array or a Collection in advance and only call the above if it is an array, here are some options for doing that:
boolean isArray = myArray.getClass().isArray();
boolean isCollection = Collection.class.isAssignableFrom(myList.getClass());
3
Arrays.asList()
will sadly not work with primitive arrays
– Lino
4 hours ago
1
Agreed, but I'm making the assumption here that the OP is not using primitive arrays. If they are they could do something likeInteger boxedInts = IntStream.of(ints).boxed().toArray(Integer::new);
(Assuming they aren't using a byte array, in which case it gets more complex)
– Ardesco
4 hours ago
add a comment |
Arrays extend Object:
https://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html
AbstractCollections also extend Object:
https://docs.oracle.com/javase/8/docs/api/java/util/AbstractCollection.html
So yes there is a common superclass, but unfortunately this isn't really going to help you.
I would suggest your best bet is to use:
List<> someList = Arrays.asList(sourceArray)
This will convert your array into a collection that implements Iterable. You will of course need to work out if the initial object is an Array or a Collection in advance and only call the above if it is an array, here are some options for doing that:
boolean isArray = myArray.getClass().isArray();
boolean isCollection = Collection.class.isAssignableFrom(myList.getClass());
Arrays extend Object:
https://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html
AbstractCollections also extend Object:
https://docs.oracle.com/javase/8/docs/api/java/util/AbstractCollection.html
So yes there is a common superclass, but unfortunately this isn't really going to help you.
I would suggest your best bet is to use:
List<> someList = Arrays.asList(sourceArray)
This will convert your array into a collection that implements Iterable. You will of course need to work out if the initial object is an Array or a Collection in advance and only call the above if it is an array, here are some options for doing that:
boolean isArray = myArray.getClass().isArray();
boolean isCollection = Collection.class.isAssignableFrom(myList.getClass());
edited 44 mins ago
answered 4 hours ago
ArdescoArdesco
5,3981744
5,3981744
3
Arrays.asList()
will sadly not work with primitive arrays
– Lino
4 hours ago
1
Agreed, but I'm making the assumption here that the OP is not using primitive arrays. If they are they could do something likeInteger boxedInts = IntStream.of(ints).boxed().toArray(Integer::new);
(Assuming they aren't using a byte array, in which case it gets more complex)
– Ardesco
4 hours ago
add a comment |
3
Arrays.asList()
will sadly not work with primitive arrays
– Lino
4 hours ago
1
Agreed, but I'm making the assumption here that the OP is not using primitive arrays. If they are they could do something likeInteger boxedInts = IntStream.of(ints).boxed().toArray(Integer::new);
(Assuming they aren't using a byte array, in which case it gets more complex)
– Ardesco
4 hours ago
3
3
Arrays.asList()
will sadly not work with primitive arrays– Lino
4 hours ago
Arrays.asList()
will sadly not work with primitive arrays– Lino
4 hours ago
1
1
Agreed, but I'm making the assumption here that the OP is not using primitive arrays. If they are they could do something like
Integer boxedInts = IntStream.of(ints).boxed().toArray(Integer::new);
(Assuming they aren't using a byte array, in which case it gets more complex)– Ardesco
4 hours ago
Agreed, but I'm making the assumption here that the OP is not using primitive arrays. If they are they could do something like
Integer boxedInts = IntStream.of(ints).boxed().toArray(Integer::new);
(Assuming they aren't using a byte array, in which case it gets more complex)– Ardesco
4 hours ago
add a comment |
You could write a helper method for this:
@SuppressWarnings("unchecked")
public static <E> void forEach(Object arrayOrIterable, Consumer<? super E> action) {
Objects.requireNonNull(arrayOrIterable);
if (arrayOrIterable instanceof Iterable) {
for (Object o : (Iterable<?>) arrayOrIterable) {
action.accept((E) o);
}
} else if (arrayOrIterable.getClass().isArray()) {
int length = Array.getLength(arrayOrIterable);
for (int i = 0; i < length; i++) {
action.accept((E) Array.get(arrayOrIterable, i));
}
} else {
throw new IllegalArgumentException("not an array nor iterable: " + arrayOrIterable.getClass());
}
}
The second branch makes use of the java.reflect.Array
class which provides helper methods (may be slow), to get the length
of an array and the element at a given index.
You may call it like this:
int ints = {1, 2, 3, 4};
forEach(ints, (Integer i) -> System.out.println(i));
List<Integer> ints = Arrays.asList(1, 2, 3, 4);
forEach(ints, (Integer i) -> System.out.println(i));
Due to the nature of generics, this method may throw a ClassCastException
, e.g. this call:
int ints = {1, 2, 3, 4};
forEach(ints, (String s) -> System.out.println(s));
Would result in:
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
I wouldn't dare to name the parameterarrayOrIterable
since it's anObject
and it might be anything
– Andrew Tobilko
4 hours ago
1
@AndrewTobilko Well this method only works with an array or an iterable, and will throw an exception for every otherObject
, so this should help as documentation that really one of those two types is expected
– Lino
4 hours ago
oh, I get you. It's a matter of personal preference/style, I guess.
– Andrew Tobilko
4 hours ago
2
@AndrewTobilko It really is something that is purely opinion based, best would be of course an extensive java-doc stating what can be passed into this method, what exceptions may be thrown etc.
– Lino
4 hours ago
add a comment |
You could write a helper method for this:
@SuppressWarnings("unchecked")
public static <E> void forEach(Object arrayOrIterable, Consumer<? super E> action) {
Objects.requireNonNull(arrayOrIterable);
if (arrayOrIterable instanceof Iterable) {
for (Object o : (Iterable<?>) arrayOrIterable) {
action.accept((E) o);
}
} else if (arrayOrIterable.getClass().isArray()) {
int length = Array.getLength(arrayOrIterable);
for (int i = 0; i < length; i++) {
action.accept((E) Array.get(arrayOrIterable, i));
}
} else {
throw new IllegalArgumentException("not an array nor iterable: " + arrayOrIterable.getClass());
}
}
The second branch makes use of the java.reflect.Array
class which provides helper methods (may be slow), to get the length
of an array and the element at a given index.
You may call it like this:
int ints = {1, 2, 3, 4};
forEach(ints, (Integer i) -> System.out.println(i));
List<Integer> ints = Arrays.asList(1, 2, 3, 4);
forEach(ints, (Integer i) -> System.out.println(i));
Due to the nature of generics, this method may throw a ClassCastException
, e.g. this call:
int ints = {1, 2, 3, 4};
forEach(ints, (String s) -> System.out.println(s));
Would result in:
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
I wouldn't dare to name the parameterarrayOrIterable
since it's anObject
and it might be anything
– Andrew Tobilko
4 hours ago
1
@AndrewTobilko Well this method only works with an array or an iterable, and will throw an exception for every otherObject
, so this should help as documentation that really one of those two types is expected
– Lino
4 hours ago
oh, I get you. It's a matter of personal preference/style, I guess.
– Andrew Tobilko
4 hours ago
2
@AndrewTobilko It really is something that is purely opinion based, best would be of course an extensive java-doc stating what can be passed into this method, what exceptions may be thrown etc.
– Lino
4 hours ago
add a comment |
You could write a helper method for this:
@SuppressWarnings("unchecked")
public static <E> void forEach(Object arrayOrIterable, Consumer<? super E> action) {
Objects.requireNonNull(arrayOrIterable);
if (arrayOrIterable instanceof Iterable) {
for (Object o : (Iterable<?>) arrayOrIterable) {
action.accept((E) o);
}
} else if (arrayOrIterable.getClass().isArray()) {
int length = Array.getLength(arrayOrIterable);
for (int i = 0; i < length; i++) {
action.accept((E) Array.get(arrayOrIterable, i));
}
} else {
throw new IllegalArgumentException("not an array nor iterable: " + arrayOrIterable.getClass());
}
}
The second branch makes use of the java.reflect.Array
class which provides helper methods (may be slow), to get the length
of an array and the element at a given index.
You may call it like this:
int ints = {1, 2, 3, 4};
forEach(ints, (Integer i) -> System.out.println(i));
List<Integer> ints = Arrays.asList(1, 2, 3, 4);
forEach(ints, (Integer i) -> System.out.println(i));
Due to the nature of generics, this method may throw a ClassCastException
, e.g. this call:
int ints = {1, 2, 3, 4};
forEach(ints, (String s) -> System.out.println(s));
Would result in:
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
You could write a helper method for this:
@SuppressWarnings("unchecked")
public static <E> void forEach(Object arrayOrIterable, Consumer<? super E> action) {
Objects.requireNonNull(arrayOrIterable);
if (arrayOrIterable instanceof Iterable) {
for (Object o : (Iterable<?>) arrayOrIterable) {
action.accept((E) o);
}
} else if (arrayOrIterable.getClass().isArray()) {
int length = Array.getLength(arrayOrIterable);
for (int i = 0; i < length; i++) {
action.accept((E) Array.get(arrayOrIterable, i));
}
} else {
throw new IllegalArgumentException("not an array nor iterable: " + arrayOrIterable.getClass());
}
}
The second branch makes use of the java.reflect.Array
class which provides helper methods (may be slow), to get the length
of an array and the element at a given index.
You may call it like this:
int ints = {1, 2, 3, 4};
forEach(ints, (Integer i) -> System.out.println(i));
List<Integer> ints = Arrays.asList(1, 2, 3, 4);
forEach(ints, (Integer i) -> System.out.println(i));
Due to the nature of generics, this method may throw a ClassCastException
, e.g. this call:
int ints = {1, 2, 3, 4};
forEach(ints, (String s) -> System.out.println(s));
Would result in:
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
edited 2 hours ago
answered 4 hours ago
LinoLino
11.4k22344
11.4k22344
I wouldn't dare to name the parameterarrayOrIterable
since it's anObject
and it might be anything
– Andrew Tobilko
4 hours ago
1
@AndrewTobilko Well this method only works with an array or an iterable, and will throw an exception for every otherObject
, so this should help as documentation that really one of those two types is expected
– Lino
4 hours ago
oh, I get you. It's a matter of personal preference/style, I guess.
– Andrew Tobilko
4 hours ago
2
@AndrewTobilko It really is something that is purely opinion based, best would be of course an extensive java-doc stating what can be passed into this method, what exceptions may be thrown etc.
– Lino
4 hours ago
add a comment |
I wouldn't dare to name the parameterarrayOrIterable
since it's anObject
and it might be anything
– Andrew Tobilko
4 hours ago
1
@AndrewTobilko Well this method only works with an array or an iterable, and will throw an exception for every otherObject
, so this should help as documentation that really one of those two types is expected
– Lino
4 hours ago
oh, I get you. It's a matter of personal preference/style, I guess.
– Andrew Tobilko
4 hours ago
2
@AndrewTobilko It really is something that is purely opinion based, best would be of course an extensive java-doc stating what can be passed into this method, what exceptions may be thrown etc.
– Lino
4 hours ago
I wouldn't dare to name the parameter
arrayOrIterable
since it's an Object
and it might be anything– Andrew Tobilko
4 hours ago
I wouldn't dare to name the parameter
arrayOrIterable
since it's an Object
and it might be anything– Andrew Tobilko
4 hours ago
1
1
@AndrewTobilko Well this method only works with an array or an iterable, and will throw an exception for every other
Object
, so this should help as documentation that really one of those two types is expected– Lino
4 hours ago
@AndrewTobilko Well this method only works with an array or an iterable, and will throw an exception for every other
Object
, so this should help as documentation that really one of those two types is expected– Lino
4 hours ago
oh, I get you. It's a matter of personal preference/style, I guess.
– Andrew Tobilko
4 hours ago
oh, I get you. It's a matter of personal preference/style, I guess.
– Andrew Tobilko
4 hours ago
2
2
@AndrewTobilko It really is something that is purely opinion based, best would be of course an extensive java-doc stating what can be passed into this method, what exceptions may be thrown etc.
– Lino
4 hours ago
@AndrewTobilko It really is something that is purely opinion based, best would be of course an extensive java-doc stating what can be passed into this method, what exceptions may be thrown etc.
– Lino
4 hours ago
add a comment |
Depending on what you are trying to do, you might want to implement two similar methods:
public <T> void iterateOver(List<T> list) {
// do whatever you want to do with your list
}
public <T> void iterateOver(T array) {
this.iterateOver(Arrays.asList(array));
}
Or maybe even have an interface for this:
interface ExtendedIterableConsumer<T> {
public void iterateOver(List<T> list);
public default void iterateOver(T array) {
this.iterateOver(Arrays.asList(array));
}
I am not sure if that helps you, because you seem to already have the object in question in a variable somewhere. But if you can address that problem one level higher, it might be useful.
1
+1 because it's already too late to try to solve the problem in the method. The architecture should probably be slightly changed.
– Eric Duminil
1 hour ago
add a comment |
Depending on what you are trying to do, you might want to implement two similar methods:
public <T> void iterateOver(List<T> list) {
// do whatever you want to do with your list
}
public <T> void iterateOver(T array) {
this.iterateOver(Arrays.asList(array));
}
Or maybe even have an interface for this:
interface ExtendedIterableConsumer<T> {
public void iterateOver(List<T> list);
public default void iterateOver(T array) {
this.iterateOver(Arrays.asList(array));
}
I am not sure if that helps you, because you seem to already have the object in question in a variable somewhere. But if you can address that problem one level higher, it might be useful.
1
+1 because it's already too late to try to solve the problem in the method. The architecture should probably be slightly changed.
– Eric Duminil
1 hour ago
add a comment |
Depending on what you are trying to do, you might want to implement two similar methods:
public <T> void iterateOver(List<T> list) {
// do whatever you want to do with your list
}
public <T> void iterateOver(T array) {
this.iterateOver(Arrays.asList(array));
}
Or maybe even have an interface for this:
interface ExtendedIterableConsumer<T> {
public void iterateOver(List<T> list);
public default void iterateOver(T array) {
this.iterateOver(Arrays.asList(array));
}
I am not sure if that helps you, because you seem to already have the object in question in a variable somewhere. But if you can address that problem one level higher, it might be useful.
Depending on what you are trying to do, you might want to implement two similar methods:
public <T> void iterateOver(List<T> list) {
// do whatever you want to do with your list
}
public <T> void iterateOver(T array) {
this.iterateOver(Arrays.asList(array));
}
Or maybe even have an interface for this:
interface ExtendedIterableConsumer<T> {
public void iterateOver(List<T> list);
public default void iterateOver(T array) {
this.iterateOver(Arrays.asList(array));
}
I am not sure if that helps you, because you seem to already have the object in question in a variable somewhere. But if you can address that problem one level higher, it might be useful.
edited 1 hour ago
answered 2 hours ago
glglglglglgl
68.1k796169
68.1k796169
1
+1 because it's already too late to try to solve the problem in the method. The architecture should probably be slightly changed.
– Eric Duminil
1 hour ago
add a comment |
1
+1 because it's already too late to try to solve the problem in the method. The architecture should probably be slightly changed.
– Eric Duminil
1 hour ago
1
1
+1 because it's already too late to try to solve the problem in the method. The architecture should probably be slightly changed.
– Eric Duminil
1 hour ago
+1 because it's already too late to try to solve the problem in the method. The architecture should probably be slightly changed.
– Eric Duminil
1 hour ago
add a comment |
The other answers are all trying hard to answer the title question, but your real question is in the body. The answer is: No, there's no way to write a single for
loop that iterates over both collections and arrays.
You could jump through a bunch of hoops to turn the arrays into lists, but you'll almost certainly end up with a bigger mess than if you just wrote two (or more) loops. Calling getClass().isArray()
tells you what you have but you still can't work with it without some sort of cast. Arrays.asList()
doesn't work for arrays of primitives.
add a comment |
The other answers are all trying hard to answer the title question, but your real question is in the body. The answer is: No, there's no way to write a single for
loop that iterates over both collections and arrays.
You could jump through a bunch of hoops to turn the arrays into lists, but you'll almost certainly end up with a bigger mess than if you just wrote two (or more) loops. Calling getClass().isArray()
tells you what you have but you still can't work with it without some sort of cast. Arrays.asList()
doesn't work for arrays of primitives.
add a comment |
The other answers are all trying hard to answer the title question, but your real question is in the body. The answer is: No, there's no way to write a single for
loop that iterates over both collections and arrays.
You could jump through a bunch of hoops to turn the arrays into lists, but you'll almost certainly end up with a bigger mess than if you just wrote two (or more) loops. Calling getClass().isArray()
tells you what you have but you still can't work with it without some sort of cast. Arrays.asList()
doesn't work for arrays of primitives.
The other answers are all trying hard to answer the title question, but your real question is in the body. The answer is: No, there's no way to write a single for
loop that iterates over both collections and arrays.
You could jump through a bunch of hoops to turn the arrays into lists, but you'll almost certainly end up with a bigger mess than if you just wrote two (or more) loops. Calling getClass().isArray()
tells you what you have but you still can't work with it without some sort of cast. Arrays.asList()
doesn't work for arrays of primitives.
answered 21 mins ago
John KugelmanJohn Kugelman
248k54406460
248k54406460
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55588278%2fcan-i-write-a-for-loop-that-iterates-over-both-collections-and-arrays%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
The way I see it,
foo
must be declared asObject
. So you have to cast anyway. Are you trying to cast just once?– ernest_k
5 hours ago
The foreach-loop won't work if I cast it to Object -- you cannot iterate through objects.
– Pawel Os.
4 hours ago
That's exactly the point I'm trying to make.
– ernest_k
4 hours ago
6
It's a good idea to avoid a design that leads to this in the first place. Even if you had a common interface for this to work with just one for-each loop, you'd still have many type casts. Your code wouldn't be type-safe (
Object
? rawIterable
?)– ernest_k
4 hours ago
I've changed the question title to better match the body.
– John Kugelman
15 mins ago