I'm confused by a bit of Java 8's type inference. The following code:
private static <T> Function<Iterable<? extends T>, Iterator<? extends T>>
toIterator() {
return Iterable<? extends T>::iterator;
}
breaks with the compile error
error: incompatible types: invalid method reference
return Iterable<? extends T>::iterator;
^
method iterator in interface Iterable<T#2> cannot be applied to given types
required: no arguments
found: Iterable<? extends T#1>
reason: actual and formal argument lists differ in length
where T#1,T#2 are type-variables:
T#1 extends Object declared in method <T#1>toIterator()
T#2 extends Object declared in interface Iterable
whereas removing the explicit generic
private static <T> Function<Iterable<? extends T>, Iterator<? extends T>>
toIterator() {
return Iterable::iterator;
}
works, as does the old-school anonymous inner class
private static <T> Function<Iterable<? extends T>, Iterator<? extends T>>
toIterator() {
return new Function<Iterable<? extends T>, Iterator<? extends T>>() {
@Override
public Iterator<? extends T> apply(Iterable<? extends T> iterable) {
return iterable.iterator();
}
};
}
Can anyone suggest what might be going on here?
Using <? extends T>
is wrong because for Generic invocations with explicit type arguments you have to specify complete types, not wildcard types.
If you simply use
private static <T> Function<Iterable<? extends T>, Iterator<? extends T>>
toIterator() {
return Iterable::iterator;
}
Java will infer the type for you.
A solution would be:
private static <T> Function<Iterable<T>, Iterator<? extends T>> toIterator() {
return Iterable<T>::iterator;
}
though it is not clear what the advantage of widening the Function
’s return type to ? extends T
shall be. For practical uses,
private static <T> Function<Iterable<T>, Iterator<T>> toIterator() {
return Iterable<T>::iterator;
}
will be the most useful method signature. For this, the inferring Iterable::iterator
still works as well.
Regarding the compiler error message, this seems just to be a bug in the error reporting which applies always when a method reference to a non-static
method has a type mismatch. It can be reproduced even by the simple statement:
Consumer<Object> c=String::getClass;
which produces the error message:
error: incompatible types: invalid method reference
Consumer<Object> c=String::getClass;
^
method getClass in class Object cannot be applied to given types
required: no arguments
found: Object
reason: actual and formal argument lists differ in length
Note that references to static
methods get the right error message:
Consumer<Object> c=Class::forName;
produces:
error: incompatible types: invalid method reference
Consumer<Object> c=Class::forName;
^
incompatible types: Object cannot be converted to String
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With