Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterating generic array of any type in Java

If there is an instance of Java Collection which may carry primitive type, generic array, and/or iterable collection, I want to treat the generic array as Iterable collection, but how? e.g. the following pseudo java code

List<?> list1; 
list1.add(new int[2]); 
list1.add(new String[3]); 
list1.add(new ArrayList());
for (Object e : list1){
    if (e instanceof Iterable){ 
        //The int[2] and String[3] will not fall in this case that I want it be
        //Iterate within e
    }
}

Please advise how to make the int[2] and String[3] fall in the case.

Thanks & regards, William

like image 267
William X Avatar asked Dec 03 '10 04:12

William X


People also ask

Can we use generics with array in Java?

Java allows generic classes, methods, etc. that can be declared independent of types. However, Java does not allow the array to be generic. The reason for this is that in Java, arrays contain information related to their components and this information is used to allocate memory at runtime.

How do you create an array of generic classes in Java?

You can do this: E[] arr = (E[])new Object[INITIAL_ARRAY_LENGTH]; This is one of the suggested ways of implementing a generic collection in Effective Java; Item 26. No type errors, no need to cast the array repeatedly.

Why is generic array creation not allowed in Java?

If generic array creation were legal, then compiler generated casts would correct the program at compile time but it can fail at runtime, which violates the core fundamental system of generic types.


2 Answers

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));
            }
        }
    }
like image 92
Petro Semeniuk Avatar answered Oct 27 '22 00:10

Petro Semeniuk


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.

like image 24
Asaph Avatar answered Oct 27 '22 01:10

Asaph