Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Upper bounded wildcard, iterator and for-each loop

I don't understand why this code compiles:

public void test(Collection<? extends Enum> enumCollection) {
    for (Enum e : enumCollection) {
    }
}

and this one does not:

public void test(Collection<? extends Enum> enumCollection) {
    Iterator<Enum> iterator = enumCollection.iterator();
    //Required: Iterator<Java.lang.Enum>
    //Found: Iterator<capture<? extends Java.lang.Enum>>
}

? extends Enum should be a subtype of Enum in all cases, so why am I getting a compilation error with the iterator and why does it work with a for-each loop?

like image 721
user2572030 Avatar asked Dec 19 '22 08:12

user2572030


1 Answers

I often find that the adage if you need to use ? in your generic you are probably doing something wrong applies.

This works fine:

public <T extends Enum<T>> void test(Collection<T> enumCollection) {
    for (Enum e : enumCollection) {
    }
    Iterator<T> iterator = enumCollection.iterator();
}

Your problem is that you are expecting generics to act like ordinary code where an ArrayList is also a List. It is not designed for that. Generics are to ensure that you are using the same type, not just some compatible type.

In your case - to match the ? extends Enum you could use:

    Iterator<?> iterator = enumCollection.iterator();

which works fine.

Your types do not match - and generics are there to make sure they do.

Remember that ? does not mean I don't care what type it is it means I don't want to know what type it is. Using ? in a generic type and then expecting to be able to make use of the type is just silly.

like image 93
OldCurmudgeon Avatar answered Dec 29 '22 01:12

OldCurmudgeon