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
yesterday
The foreach-loop won't work if I cast it to Object -- you cannot iterate through objects.
– Pawel Os.
yesterday
8
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
yesterday
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 yesterday
John Kugelman
248k54406460
248k54406460
asked yesterday
Pawel Os.Pawel Os.
162116
162116
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
yesterday
The foreach-loop won't work if I cast it to Object -- you cannot iterate through objects.
– Pawel Os.
yesterday
8
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
yesterday
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
yesterday
The foreach-loop won't work if I cast it to Object -- you cannot iterate through objects.
– Pawel Os.
yesterday
8
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
yesterday
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
yesterday
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
yesterday
The foreach-loop won't work if I cast it to Object -- you cannot iterate through objects.
– Pawel Os.
yesterday
The foreach-loop won't work if I cast it to Object -- you cannot iterate through objects.
– Pawel Os.
yesterday
8
8
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
yesterday
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
yesterday
add a comment |
6 Answers
6
active
oldest
votes
The other answers are all trying hard to answer the original title question:
Is there a common interface or superclass for arrays and collections?
But your real question is in the body:
Are there any other possibilities to handle both in one loop like the above?
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.
Thank you for this response. It's a pity that you cannot abstract from Arrays/Collection and primitive/objects in Java, as the loop construction would remain the same and would make the code more readable. But I guess that's just the way it is and we have to live with it.
– Pawel Os.
17 hours ago
add a comment |
Regarding a condition to check if foo
is either a collection or an array:
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. Having no particular context, I can come up with a simple idea of two subclasses, each of which defining how its source (either a collection or an array) should be iterated. Then, programming to an interface will help to manage them equally.
A very simplified example would be:
interface Abstraction<T> {
void iterate(Consumer<? super T> action);
static <T> Abstraction<T> of(Collection<T> collection) {
return new CollectionAbstraction<>(collection);
}
static <T> Abstraction<T> of(T array) {
return new ArrayAbstraction<>(array);
}
static IntArrayAbstraction of(int array) {
return new IntArrayAbstraction(array);
}
}
class CollectionAbstraction<T> implements Abstraction<T> {
Collection<T> source;
public CollectionAbstraction(Collection<T> source) {
this.source = source;
}
@Override
public void iterate(Consumer<? super T> action) {
source.forEach(action);
}
}
class ArrayAbstraction<T> implements Abstraction<T> {
T source;
public ArrayAbstraction(T source) {
this.source = source;
}
@Override
public void iterate(Consumer<? super T> action) {
for (T t : source) {
action.accept(t);
}
}
}
class IntArrayAbstraction implements Abstraction<Integer> {
int source;
public IntArrayAbstraction(int source) {
this.source = source;
}
@Override
public void iterate(Consumer<? super Integer> action) {
for (int t : source) {
action.accept(t);
}
}
}
class Test {
public static void main(String args) {
Abstraction.of(new Integer {1, 2, 3}).iterate(System.out::println);
Abstraction.of(Arrays.asList(1, 2, 3)).iterate(System.out::println);
Abstraction.of(new int {1, 2, 3}).iterate(System.out::println);
}
}
I believe the approach above is pretty versatile. You don't depend on how a certain source is iterated, you may selectively modify them.
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
yesterday
3
@JohnBollinger I thought it was obvious from the comments that there is no neat solution, so I dropped that part. Now I elaborated on this in the last paragraphs.
– Andrew Tobilko
yesterday
1
The abstraction described in the second half of this answer is unnecessary, because something equivalent already exists in the standard library. Just replaceAbstraction
withCollection
, andAbstraction.of(T)
withArrays.asList
.
– David
yesterday
@David what would you replaceAbstraction
with for arrays of primitives?
– Andrew Tobilko
20 hours ago
Abstraction
doesn't work on arrays of primitives becauseT
has to be a subclass ofObject
. Changenew Integer
tonew int
and it fails to compile.
– John Kugelman
14 hours ago
|
show 2 more comments
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.
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
yesterday
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
yesterday
oh, I get you. It's a matter of personal preference/style, I guess.
– Andrew Tobilko
yesterday
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
yesterday
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<?>)){
}
Edit:
In terms of iterating over this foo
object, there is no simple solution. However you could try something like this:
private void iterate(@NotNull Object foo) {
if (foo instanceof Collection<?>) {
for (Object o : ((Collection<?>) foo)) {
chandleYourObject(o);
}
}
if (foo.getClass().isArray()) {
if (foo.getClass().isPrimitive()) {
checkPrimitiveTypes(foo);
}
if (foo instanceof Object) {
for (Object o : (Object) foo) {
chandleYourObject(o);
}
}
}
}
private void checkPrimitiveTypes(Object foo) {
if (foo instanceof int) {
for (int i : (int) foo) {
}
}
//And the rest of primitive types
}
private void chandleYourObject(Object o ){
//What you want to do with your object
}
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
yesterday
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
yesterday
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
yesterday
add a comment |
Arrays are Objects:
https://docs.oracle.com/javase/specs/jls/se8/html/jls-10.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());
4
Arrays.asList()
will sadly not work with primitive arrays
– Lino
yesterday
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
yesterday
1
Arrays
is a utility class that "contains various methods for manipulating arrays". It is not the superclass of arrays.
– Solomon Ucko
yesterday
1
True, updated the answer to point towards Java documentation that states Arrays are Objects instead,
– Ardesco
yesterday
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
The other answers are all trying hard to answer the original title question:
Is there a common interface or superclass for arrays and collections?
But your real question is in the body:
Are there any other possibilities to handle both in one loop like the above?
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.
Thank you for this response. It's a pity that you cannot abstract from Arrays/Collection and primitive/objects in Java, as the loop construction would remain the same and would make the code more readable. But I guess that's just the way it is and we have to live with it.
– Pawel Os.
17 hours ago
add a comment |
The other answers are all trying hard to answer the original title question:
Is there a common interface or superclass for arrays and collections?
But your real question is in the body:
Are there any other possibilities to handle both in one loop like the above?
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.
Thank you for this response. It's a pity that you cannot abstract from Arrays/Collection and primitive/objects in Java, as the loop construction would remain the same and would make the code more readable. But I guess that's just the way it is and we have to live with it.
– Pawel Os.
17 hours ago
add a comment |
The other answers are all trying hard to answer the original title question:
Is there a common interface or superclass for arrays and collections?
But your real question is in the body:
Are there any other possibilities to handle both in one loop like the above?
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 original title question:
Is there a common interface or superclass for arrays and collections?
But your real question is in the body:
Are there any other possibilities to handle both in one loop like the above?
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.
edited yesterday
answered yesterday
John KugelmanJohn Kugelman
248k54406460
248k54406460
Thank you for this response. It's a pity that you cannot abstract from Arrays/Collection and primitive/objects in Java, as the loop construction would remain the same and would make the code more readable. But I guess that's just the way it is and we have to live with it.
– Pawel Os.
17 hours ago
add a comment |
Thank you for this response. It's a pity that you cannot abstract from Arrays/Collection and primitive/objects in Java, as the loop construction would remain the same and would make the code more readable. But I guess that's just the way it is and we have to live with it.
– Pawel Os.
17 hours ago
Thank you for this response. It's a pity that you cannot abstract from Arrays/Collection and primitive/objects in Java, as the loop construction would remain the same and would make the code more readable. But I guess that's just the way it is and we have to live with it.
– Pawel Os.
17 hours ago
Thank you for this response. It's a pity that you cannot abstract from Arrays/Collection and primitive/objects in Java, as the loop construction would remain the same and would make the code more readable. But I guess that's just the way it is and we have to live with it.
– Pawel Os.
17 hours ago
add a comment |
Regarding a condition to check if foo
is either a collection or an array:
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. Having no particular context, I can come up with a simple idea of two subclasses, each of which defining how its source (either a collection or an array) should be iterated. Then, programming to an interface will help to manage them equally.
A very simplified example would be:
interface Abstraction<T> {
void iterate(Consumer<? super T> action);
static <T> Abstraction<T> of(Collection<T> collection) {
return new CollectionAbstraction<>(collection);
}
static <T> Abstraction<T> of(T array) {
return new ArrayAbstraction<>(array);
}
static IntArrayAbstraction of(int array) {
return new IntArrayAbstraction(array);
}
}
class CollectionAbstraction<T> implements Abstraction<T> {
Collection<T> source;
public CollectionAbstraction(Collection<T> source) {
this.source = source;
}
@Override
public void iterate(Consumer<? super T> action) {
source.forEach(action);
}
}
class ArrayAbstraction<T> implements Abstraction<T> {
T source;
public ArrayAbstraction(T source) {
this.source = source;
}
@Override
public void iterate(Consumer<? super T> action) {
for (T t : source) {
action.accept(t);
}
}
}
class IntArrayAbstraction implements Abstraction<Integer> {
int source;
public IntArrayAbstraction(int source) {
this.source = source;
}
@Override
public void iterate(Consumer<? super Integer> action) {
for (int t : source) {
action.accept(t);
}
}
}
class Test {
public static void main(String args) {
Abstraction.of(new Integer {1, 2, 3}).iterate(System.out::println);
Abstraction.of(Arrays.asList(1, 2, 3)).iterate(System.out::println);
Abstraction.of(new int {1, 2, 3}).iterate(System.out::println);
}
}
I believe the approach above is pretty versatile. You don't depend on how a certain source is iterated, you may selectively modify them.
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
yesterday
3
@JohnBollinger I thought it was obvious from the comments that there is no neat solution, so I dropped that part. Now I elaborated on this in the last paragraphs.
– Andrew Tobilko
yesterday
1
The abstraction described in the second half of this answer is unnecessary, because something equivalent already exists in the standard library. Just replaceAbstraction
withCollection
, andAbstraction.of(T)
withArrays.asList
.
– David
yesterday
@David what would you replaceAbstraction
with for arrays of primitives?
– Andrew Tobilko
20 hours ago
Abstraction
doesn't work on arrays of primitives becauseT
has to be a subclass ofObject
. Changenew Integer
tonew int
and it fails to compile.
– John Kugelman
14 hours ago
|
show 2 more comments
Regarding a condition to check if foo
is either a collection or an array:
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. Having no particular context, I can come up with a simple idea of two subclasses, each of which defining how its source (either a collection or an array) should be iterated. Then, programming to an interface will help to manage them equally.
A very simplified example would be:
interface Abstraction<T> {
void iterate(Consumer<? super T> action);
static <T> Abstraction<T> of(Collection<T> collection) {
return new CollectionAbstraction<>(collection);
}
static <T> Abstraction<T> of(T array) {
return new ArrayAbstraction<>(array);
}
static IntArrayAbstraction of(int array) {
return new IntArrayAbstraction(array);
}
}
class CollectionAbstraction<T> implements Abstraction<T> {
Collection<T> source;
public CollectionAbstraction(Collection<T> source) {
this.source = source;
}
@Override
public void iterate(Consumer<? super T> action) {
source.forEach(action);
}
}
class ArrayAbstraction<T> implements Abstraction<T> {
T source;
public ArrayAbstraction(T source) {
this.source = source;
}
@Override
public void iterate(Consumer<? super T> action) {
for (T t : source) {
action.accept(t);
}
}
}
class IntArrayAbstraction implements Abstraction<Integer> {
int source;
public IntArrayAbstraction(int source) {
this.source = source;
}
@Override
public void iterate(Consumer<? super Integer> action) {
for (int t : source) {
action.accept(t);
}
}
}
class Test {
public static void main(String args) {
Abstraction.of(new Integer {1, 2, 3}).iterate(System.out::println);
Abstraction.of(Arrays.asList(1, 2, 3)).iterate(System.out::println);
Abstraction.of(new int {1, 2, 3}).iterate(System.out::println);
}
}
I believe the approach above is pretty versatile. You don't depend on how a certain source is iterated, you may selectively modify them.
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
yesterday
3
@JohnBollinger I thought it was obvious from the comments that there is no neat solution, so I dropped that part. Now I elaborated on this in the last paragraphs.
– Andrew Tobilko
yesterday
1
The abstraction described in the second half of this answer is unnecessary, because something equivalent already exists in the standard library. Just replaceAbstraction
withCollection
, andAbstraction.of(T)
withArrays.asList
.
– David
yesterday
@David what would you replaceAbstraction
with for arrays of primitives?
– Andrew Tobilko
20 hours ago
Abstraction
doesn't work on arrays of primitives becauseT
has to be a subclass ofObject
. Changenew Integer
tonew int
and it fails to compile.
– John Kugelman
14 hours ago
|
show 2 more comments
Regarding a condition to check if foo
is either a collection or an array:
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. Having no particular context, I can come up with a simple idea of two subclasses, each of which defining how its source (either a collection or an array) should be iterated. Then, programming to an interface will help to manage them equally.
A very simplified example would be:
interface Abstraction<T> {
void iterate(Consumer<? super T> action);
static <T> Abstraction<T> of(Collection<T> collection) {
return new CollectionAbstraction<>(collection);
}
static <T> Abstraction<T> of(T array) {
return new ArrayAbstraction<>(array);
}
static IntArrayAbstraction of(int array) {
return new IntArrayAbstraction(array);
}
}
class CollectionAbstraction<T> implements Abstraction<T> {
Collection<T> source;
public CollectionAbstraction(Collection<T> source) {
this.source = source;
}
@Override
public void iterate(Consumer<? super T> action) {
source.forEach(action);
}
}
class ArrayAbstraction<T> implements Abstraction<T> {
T source;
public ArrayAbstraction(T source) {
this.source = source;
}
@Override
public void iterate(Consumer<? super T> action) {
for (T t : source) {
action.accept(t);
}
}
}
class IntArrayAbstraction implements Abstraction<Integer> {
int source;
public IntArrayAbstraction(int source) {
this.source = source;
}
@Override
public void iterate(Consumer<? super Integer> action) {
for (int t : source) {
action.accept(t);
}
}
}
class Test {
public static void main(String args) {
Abstraction.of(new Integer {1, 2, 3}).iterate(System.out::println);
Abstraction.of(Arrays.asList(1, 2, 3)).iterate(System.out::println);
Abstraction.of(new int {1, 2, 3}).iterate(System.out::println);
}
}
I believe the approach above is pretty versatile. You don't depend on how a certain source is iterated, you may selectively modify them.
Regarding a condition to check if foo
is either a collection or an array:
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. Having no particular context, I can come up with a simple idea of two subclasses, each of which defining how its source (either a collection or an array) should be iterated. Then, programming to an interface will help to manage them equally.
A very simplified example would be:
interface Abstraction<T> {
void iterate(Consumer<? super T> action);
static <T> Abstraction<T> of(Collection<T> collection) {
return new CollectionAbstraction<>(collection);
}
static <T> Abstraction<T> of(T array) {
return new ArrayAbstraction<>(array);
}
static IntArrayAbstraction of(int array) {
return new IntArrayAbstraction(array);
}
}
class CollectionAbstraction<T> implements Abstraction<T> {
Collection<T> source;
public CollectionAbstraction(Collection<T> source) {
this.source = source;
}
@Override
public void iterate(Consumer<? super T> action) {
source.forEach(action);
}
}
class ArrayAbstraction<T> implements Abstraction<T> {
T source;
public ArrayAbstraction(T source) {
this.source = source;
}
@Override
public void iterate(Consumer<? super T> action) {
for (T t : source) {
action.accept(t);
}
}
}
class IntArrayAbstraction implements Abstraction<Integer> {
int source;
public IntArrayAbstraction(int source) {
this.source = source;
}
@Override
public void iterate(Consumer<? super Integer> action) {
for (int t : source) {
action.accept(t);
}
}
}
class Test {
public static void main(String args) {
Abstraction.of(new Integer {1, 2, 3}).iterate(System.out::println);
Abstraction.of(Arrays.asList(1, 2, 3)).iterate(System.out::println);
Abstraction.of(new int {1, 2, 3}).iterate(System.out::println);
}
}
I believe the approach above is pretty versatile. You don't depend on how a certain source is iterated, you may selectively modify them.
edited 12 hours ago
answered yesterday
Andrew TobilkoAndrew Tobilko
28.6k104591
28.6k104591
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
yesterday
3
@JohnBollinger I thought it was obvious from the comments that there is no neat solution, so I dropped that part. Now I elaborated on this in the last paragraphs.
– Andrew Tobilko
yesterday
1
The abstraction described in the second half of this answer is unnecessary, because something equivalent already exists in the standard library. Just replaceAbstraction
withCollection
, andAbstraction.of(T)
withArrays.asList
.
– David
yesterday
@David what would you replaceAbstraction
with for arrays of primitives?
– Andrew Tobilko
20 hours ago
Abstraction
doesn't work on arrays of primitives becauseT
has to be a subclass ofObject
. Changenew Integer
tonew int
and it fails to compile.
– John Kugelman
14 hours ago
|
show 2 more comments
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
yesterday
3
@JohnBollinger I thought it was obvious from the comments that there is no neat solution, so I dropped that part. Now I elaborated on this in the last paragraphs.
– Andrew Tobilko
yesterday
1
The abstraction described in the second half of this answer is unnecessary, because something equivalent already exists in the standard library. Just replaceAbstraction
withCollection
, andAbstraction.of(T)
withArrays.asList
.
– David
yesterday
@David what would you replaceAbstraction
with for arrays of primitives?
– Andrew Tobilko
20 hours ago
Abstraction
doesn't work on arrays of primitives becauseT
has to be a subclass ofObject
. Changenew Integer
tonew int
and it fails to compile.
– John Kugelman
14 hours 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
yesterday
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
yesterday
3
3
@JohnBollinger I thought it was obvious from the comments that there is no neat solution, so I dropped that part. Now I elaborated on this in the last paragraphs.
– Andrew Tobilko
yesterday
@JohnBollinger I thought it was obvious from the comments that there is no neat solution, so I dropped that part. Now I elaborated on this in the last paragraphs.
– Andrew Tobilko
yesterday
1
1
The abstraction described in the second half of this answer is unnecessary, because something equivalent already exists in the standard library. Just replace
Abstraction
with Collection
, and Abstraction.of(T)
with Arrays.asList
.– David
yesterday
The abstraction described in the second half of this answer is unnecessary, because something equivalent already exists in the standard library. Just replace
Abstraction
with Collection
, and Abstraction.of(T)
with Arrays.asList
.– David
yesterday
@David what would you replace
Abstraction
with for arrays of primitives?– Andrew Tobilko
20 hours ago
@David what would you replace
Abstraction
with for arrays of primitives?– Andrew Tobilko
20 hours ago
Abstraction
doesn't work on arrays of primitives because T
has to be a subclass of Object
. Change new Integer
to new int
and it fails to compile.– John Kugelman
14 hours ago
Abstraction
doesn't work on arrays of primitives because T
has to be a subclass of Object
. Change new Integer
to new int
and it fails to compile.– John Kugelman
14 hours ago
|
show 2 more comments
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.
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.
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 yesterday
answered yesterday
glglglglglgl
68.2k796169
68.2k796169
add a comment |
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
yesterday
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
yesterday
oh, I get you. It's a matter of personal preference/style, I guess.
– Andrew Tobilko
yesterday
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
yesterday
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
yesterday
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
yesterday
oh, I get you. It's a matter of personal preference/style, I guess.
– Andrew Tobilko
yesterday
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
yesterday
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 yesterday
answered yesterday
LinoLino
11.6k22344
11.6k22344
I wouldn't dare to name the parameterarrayOrIterable
since it's anObject
and it might be anything
– Andrew Tobilko
yesterday
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
yesterday
oh, I get you. It's a matter of personal preference/style, I guess.
– Andrew Tobilko
yesterday
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
yesterday
add a comment |
I wouldn't dare to name the parameterarrayOrIterable
since it's anObject
and it might be anything
– Andrew Tobilko
yesterday
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
yesterday
oh, I get you. It's a matter of personal preference/style, I guess.
– Andrew Tobilko
yesterday
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
yesterday
I wouldn't dare to name the parameter
arrayOrIterable
since it's an Object
and it might be anything– Andrew Tobilko
yesterday
I wouldn't dare to name the parameter
arrayOrIterable
since it's an Object
and it might be anything– Andrew Tobilko
yesterday
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
yesterday
@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
yesterday
oh, I get you. It's a matter of personal preference/style, I guess.
– Andrew Tobilko
yesterday
oh, I get you. It's a matter of personal preference/style, I guess.
– Andrew Tobilko
yesterday
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
yesterday
@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
yesterday
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<?>)){
}
Edit:
In terms of iterating over this foo
object, there is no simple solution. However you could try something like this:
private void iterate(@NotNull Object foo) {
if (foo instanceof Collection<?>) {
for (Object o : ((Collection<?>) foo)) {
chandleYourObject(o);
}
}
if (foo.getClass().isArray()) {
if (foo.getClass().isPrimitive()) {
checkPrimitiveTypes(foo);
}
if (foo instanceof Object) {
for (Object o : (Object) foo) {
chandleYourObject(o);
}
}
}
}
private void checkPrimitiveTypes(Object foo) {
if (foo instanceof int) {
for (int i : (int) foo) {
}
}
//And the rest of primitive types
}
private void chandleYourObject(Object o ){
//What you want to do with your object
}
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
yesterday
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
yesterday
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
yesterday
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<?>)){
}
Edit:
In terms of iterating over this foo
object, there is no simple solution. However you could try something like this:
private void iterate(@NotNull Object foo) {
if (foo instanceof Collection<?>) {
for (Object o : ((Collection<?>) foo)) {
chandleYourObject(o);
}
}
if (foo.getClass().isArray()) {
if (foo.getClass().isPrimitive()) {
checkPrimitiveTypes(foo);
}
if (foo instanceof Object) {
for (Object o : (Object) foo) {
chandleYourObject(o);
}
}
}
}
private void checkPrimitiveTypes(Object foo) {
if (foo instanceof int) {
for (int i : (int) foo) {
}
}
//And the rest of primitive types
}
private void chandleYourObject(Object o ){
//What you want to do with your object
}
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
yesterday
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
yesterday
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
yesterday
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<?>)){
}
Edit:
In terms of iterating over this foo
object, there is no simple solution. However you could try something like this:
private void iterate(@NotNull Object foo) {
if (foo instanceof Collection<?>) {
for (Object o : ((Collection<?>) foo)) {
chandleYourObject(o);
}
}
if (foo.getClass().isArray()) {
if (foo.getClass().isPrimitive()) {
checkPrimitiveTypes(foo);
}
if (foo instanceof Object) {
for (Object o : (Object) foo) {
chandleYourObject(o);
}
}
}
}
private void checkPrimitiveTypes(Object foo) {
if (foo instanceof int) {
for (int i : (int) foo) {
}
}
//And the rest of primitive types
}
private void chandleYourObject(Object o ){
//What you want to do with your object
}
You can check if object is array by using isArray()
method from Class
if (foo != null && (foo.getClass().isArray() || foo instanceof Collection<?>)){
}
Edit:
In terms of iterating over this foo
object, there is no simple solution. However you could try something like this:
private void iterate(@NotNull Object foo) {
if (foo instanceof Collection<?>) {
for (Object o : ((Collection<?>) foo)) {
chandleYourObject(o);
}
}
if (foo.getClass().isArray()) {
if (foo.getClass().isPrimitive()) {
checkPrimitiveTypes(foo);
}
if (foo instanceof Object) {
for (Object o : (Object) foo) {
chandleYourObject(o);
}
}
}
}
private void checkPrimitiveTypes(Object foo) {
if (foo instanceof int) {
for (int i : (int) foo) {
}
}
//And the rest of primitive types
}
private void chandleYourObject(Object o ){
//What you want to do with your object
}
edited yesterday
answered yesterday
MershelMershel
280211
280211
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
yesterday
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
yesterday
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
yesterday
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
yesterday
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
yesterday
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
yesterday
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
yesterday
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
yesterday
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
yesterday
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
yesterday
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
yesterday
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
yesterday
add a comment |
Arrays are Objects:
https://docs.oracle.com/javase/specs/jls/se8/html/jls-10.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());
4
Arrays.asList()
will sadly not work with primitive arrays
– Lino
yesterday
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
yesterday
1
Arrays
is a utility class that "contains various methods for manipulating arrays". It is not the superclass of arrays.
– Solomon Ucko
yesterday
1
True, updated the answer to point towards Java documentation that states Arrays are Objects instead,
– Ardesco
yesterday
add a comment |
Arrays are Objects:
https://docs.oracle.com/javase/specs/jls/se8/html/jls-10.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());
4
Arrays.asList()
will sadly not work with primitive arrays
– Lino
yesterday
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
yesterday
1
Arrays
is a utility class that "contains various methods for manipulating arrays". It is not the superclass of arrays.
– Solomon Ucko
yesterday
1
True, updated the answer to point towards Java documentation that states Arrays are Objects instead,
– Ardesco
yesterday
add a comment |
Arrays are Objects:
https://docs.oracle.com/javase/specs/jls/se8/html/jls-10.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 are Objects:
https://docs.oracle.com/javase/specs/jls/se8/html/jls-10.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 yesterday
answered yesterday
ArdescoArdesco
5,4081744
5,4081744
4
Arrays.asList()
will sadly not work with primitive arrays
– Lino
yesterday
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
yesterday
1
Arrays
is a utility class that "contains various methods for manipulating arrays". It is not the superclass of arrays.
– Solomon Ucko
yesterday
1
True, updated the answer to point towards Java documentation that states Arrays are Objects instead,
– Ardesco
yesterday
add a comment |
4
Arrays.asList()
will sadly not work with primitive arrays
– Lino
yesterday
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
yesterday
1
Arrays
is a utility class that "contains various methods for manipulating arrays". It is not the superclass of arrays.
– Solomon Ucko
yesterday
1
True, updated the answer to point towards Java documentation that states Arrays are Objects instead,
– Ardesco
yesterday
4
4
Arrays.asList()
will sadly not work with primitive arrays– Lino
yesterday
Arrays.asList()
will sadly not work with primitive arrays– Lino
yesterday
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
yesterday
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
yesterday
1
1
Arrays
is a utility class that "contains various methods for manipulating arrays". It is not the superclass of arrays.– Solomon Ucko
yesterday
Arrays
is a utility class that "contains various methods for manipulating arrays". It is not the superclass of arrays.– Solomon Ucko
yesterday
1
1
True, updated the answer to point towards Java documentation that states Arrays are Objects instead,
– Ardesco
yesterday
True, updated the answer to point towards Java documentation that states Arrays are Objects instead,
– Ardesco
yesterday
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
yesterday
The foreach-loop won't work if I cast it to Object -- you cannot iterate through objects.
– Pawel Os.
yesterday
8
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
yesterday