I have a custom iterator interface
public interface ThrowingIterator<T, E extends Throwable> {
// matches interface of standard Iterator, but next() and hasNext() can throw E
}
and an implementation
public class CustomIterator implements ThrowingIterator<List<MyType>, IOException> {
// ...
public CustomIterator() {
// ...
}
public static ThrowingIterator<List<MyType>, IOException> helperFactory() {
// ...
}
}
where class MyType implements MyInterface
. The issue that I have is within the following function:
ThrowingIterator<List<? extends MyInterface>, IOException> getIterator() {
if (someCondition) {
return new CustomIterator();
}
return CustomIterator.helperFactory();
}
The compiler is erroring on both return statements, for different reasons. Intellij provides the following:
// first
Required: ThrowingIterator<List<? extends MyInterface>, IOException>
Provided: CustomIterator
// second
Required: ThrowingIterator<List<? extends MyInterface>, IOException>
Provided: ThrowingIterator<List<MyType>, IOException>
As far as I can tell, CustomIterator
should fit what is needed, since the type it implements for ThrowingIterator
fits within the wildcard bounds (especially looking at the second case, since MyType implements MyInterface
, which is what I thought is exactly what ? extends MyInterface
is trying to capture.) How can this generics issue be resolved while minimizing the amount of wildcards in declarations/signatures? The signature of getIterator()
is fine as-is. I also understand supplying an iterator over a list is bad practice; fixing that is handled elsewhere.
Your method getIterator
doesn't compile, because by default Java's generics are invariant.
What this means is that even though a List<MyType>
is a subtype of List<? extends MyInterface>
, a ThrowingIterator<List<MyType>, IOException>
is not a subtype of ThrowingIterator<List<? extends MyInterface>, IOException>
.
This is for the same reason that List<MyType>
is not a subtype of List<MyInterface>
- Java's generics are invariant. You made that covariant already by adding ? extends
, resulting in List<? extends MyInterface>
. Now you just have to do that again, because you've added another layer of generics that is still invariant.
Add ? extends
again:
// vvvvvvvvv
ThrowingIterator<? extends List<? extends MyInterface>, IOException>
getIterator() {
That will satisfy IntelliJ and the Java compiler.