9

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?

12
  • 3
    My best guess at this point is that Java 8 thinks that the two <? extends T> wildcards are different and won't consider the possibility that the iterable is the argument. Commented Aug 13, 2014 at 16:54
  • I don't think that is valid notation. The left hand side of :: shouldn't have type arguments. Actually...I'm going to review this statement. Commented Aug 13, 2014 at 17:03
  • @SotiriosDelimanolis In fact that compiles fine. Commented Aug 13, 2014 at 17:15
  • @RohitJain What does? Commented Aug 13, 2014 at 17:16
  • @SotiriosDelimanolis The notation Iterable<? extends T>::iterator; Commented Aug 13, 2014 at 17:16

1 Answer 1

5

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 
Sign up to request clarification or add additional context in comments.

13 Comments

Wouldn't your first snippet indicate a generic method iterator? This is an instance method that depends on the type parameter of the declaring type.
@Rohit Jain: where do you see a raw type in my answer? Method references will always use type inference to get the right Generic type.
@Rohit Jain: So why do you think my code compiles without any error in Netbeans then?
@Rohit Jain: well, I didn’t get a warning but you’re right, I can put anything into it. That should be an error then…
@Sotirios Delimanolis: Before Java 7, System.out.<Object>println() gave an error, tried with both, Oracle jdk and eclipse. Is there a reason for allowing it now and just producing a warning (sometimes).
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.