Iterating generic array of any type in Java

Use Array class from reflection package:

    final List<Object> list = new ArrayList<Object>();
    list.add(new int[] { 1, 2 });
    list.add(new String[] { "a", "b", "c" });
    final List<String> arrayList = new ArrayList<String>();
    arrayList.add("el1");
    list.add(arrayList);

    for (Object element : list) {
        if (element instanceof Iterable) {
            for (Object objectInIterable : (Iterable) element) {
                System.out.println(objectInIterable);
            }
        }
        if (element.getClass().isArray()) {
            for (int i = 0; i < Array.getLength(element); i++) {
                System.out.println(Array.get(element, i));
            }
        }
    }

Within your loop, you could use the appropriate array operand for instanceof.

For int[]:

if (e instanceof int[]) {
   // ...
}

For Object arrays (including String[]):

if (e instanceof Object[]){
    // ...
}

Alternatively, when adding your arrays to your master List, you could wrap each one in Arrays.asList(). In that case, you could use the List<List> generic instead of the wildcard generic List<?> and avoid the need to check the data type with instanceof. Something like this:

List<List> list1; 
list1.add(Arrays.asList(new int[2])); 
list1.add(Arrays.asList(new String[3])); 
list1.add(new ArrayList());
for (List e : list1){
    // no need to check instanceof Iterable because we guarantee it's a List
    for (Object object : e) {
        // ...
    }
}

Anytime you're using instanceof and generics together, it's a smell that you may be doing something not quite right with your generics.


You can't add things to a List<?>. If you want a list of heterogeneous things, use a List<Object>.

However, since you want to iterate over the things in your list, why not use a List<Iterable<Object>>? To add an array, use Arrays.asList(myarray) to get something that implements Iterable from it.

final List<Iterable<? extends Object>> list1 = new ArrayList<Iterable<? extends Object>>();

list1.add(Arrays.asList(new int[2]));
list1.add(Arrays.asList(new String[3])); 
list1.add(new ArrayList<Integer>());

for (final Iterable<? extends Object> e : list1) {
    for (final Object i : e) {
        // ...
    }
}

If you want to store non-iterable things in your list too, then you'll need to use List<Object> and the instanceof check, but you can still use Arrays.asList() to turn arrays into iterables, avoiding the need to handle arrays as a special case.