views:

119

answers:

2

I'm writing a class which has two ArrayList fields. One is for containing custom objects. The other is for containing custom collection objects (which may also have these fields):

private ArrayList<SomeClass> myObjList;                  // Just objects
private ArrayList<SomeCollectionClass> myCollectionList; // Collections of objects

In order to implement the Collection<E> interface, I wrote an iterator() method:

public Iterator<SomeClass> iterator() { ... }

But as a convenience method I also started to write a deepIterator() to return Iterators for each of the collections in myCollectionList - a collection of Iterators - and things got very messy very quickly:

public Iterator<SomeClass>[] deepIterator() {
    int numIterators = this.myCollectionList.size();
    Iterator<SomeClass>[] iters = (Iterator<SomeClass>[]) new Iterator<SomeClass>[numIterators]; // not allowed
    for (int i = 0; i <= numIterators; i++) {
        iters[i] = this.myCollectionList.get(i).iterator();
    }
    return iters;
}

and the compiler throws a "generic array creation" error. I understand why this happens, what I don't understand is why:

    public Iterator<SomeClass>[] deepIterator() {
    int numIterators = this.myCollectionList.size();
    Iterator<SomeClass>[] iters = (Iterator<SomeClass>[])(Array.newInstance(Iterator.class, numIterators)); // allowed
    for (int i = 0; i <= numIterators; i++) {
        iters[i] = this.myCollectionList.get(i).iterator();
    }
    return iters;
}

compiles just fine. Can anyone explain? I'm not really concerned about the merits of array[] versus some Collection<E> class (ArrayList or what have you) as the return type, I'm just mystified by that declare/instantiate/initialize line. Thanks in advance!

A: 

Would it help if you declared your second item like this?

private ArrayList<Collection<SomeClass>> myCollectionList;

Dealing with arrays and iterators looks like a pain in the a$$. I have nested collections inside collections using generics like this before and it works fine. Then I just use the normal collections API calls to iterate through it at the with nested for loops.

Jim Tough
A: 

The difference is that in the first snippet, you specify the iterator's type parameter when creating the array, but in the second you don't. If you use an unbounded wildcard for the type parameter:

Iterator<SomeClass>[] iters = (Iterator<SomeClass>[]) new Iterator<?>[numIterators];

or the raw type:

Iterator<SomeClass>[] iters = (Iterator<SomeClass>[]) new Iterator[numIterators];

it compiles just like the second snippet, i.e. it will merely emit an unchecked warning.

PS: Creating an array of a non-reifiable component type is prohibited by the Java Language Specification, §15.10.

PPS: Personally I'd be annoyed if an API needlessly forced me to deal with Iterator objects, as one can not use an extended for loop to iterate. If you want to expose the lists, why not as Collection (or at least Iterable)? It's easier for you and your caller.

meriton