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.
The forEach method is also used to loop through arrays, but it uses a function differently than the classic "for loop". The forEach method passes a callback function for each element of an array together with the following parameters: Current Value (required) - The value of the current array element.
For-Each Loop is another form of for loop used to traverse the array. for-each loop reduces the code significantly and there is no use of the index or rather the counter in the loop. Syntax: For(<DataType of array/List><Temp variable name> : <Array/List to be iterated>){ System.
In Java, the for-each loop is used to iterate through elements of arrays and collections (like ArrayList). It is also known as the enhanced for loop.
Looping Through a 2D Array. Since you can find out the number of rows and columns in a 2D array you can use a nested for loop (one loop inside of another loop) to loop/traverse through all of the elements of a 2D array.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With