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