Lambda Expression y método genérico

Supongamos que tengo una interfaz genérica:

interface MyComparable<T extends Comparable> { public int compare(T obj1, T obj2); } 

Y un método de sort :

 public static <T extends Comparable> void sort(List list, MyComparable comp) { // sort the list } 

Puedo invocar este método y pasar una expresión lambda como argumento:

 List list = Arrays.asList("a", "b", "c"); sort(list, (a, b) -> a.compareTo(b)); 

Eso funcionará bien.

Pero ahora si hago que la interfaz no sea genérica, y el método genérico:

 interface MyComparable { public <T extends Comparable> int compare(T obj1, T obj2); } public static <T extends Comparable> void sort(List list, MyComparable comp) { } 

Y luego invocar esto como:

 List list = Arrays.asList("a", "b", "c"); sort(list, (a, b) -> a.compareTo(b)); 

No comstack Muestra un error en la expresión lambda diciendo:

“El método de destino es genérico”

OK, cuando lo compilé usando javac , muestra el siguiente error:

 SO.java:20: error: incompatible types: cannot infer type-variable(s) T#1 sort(list, (a, b) -> a.compareTo(b)); ^ (argument mismatch; invalid functional descriptor for lambda expression method (T#2,T#2)int in interface MyComparable is generic) where T#1,T#2 are type-variables: T#1 extends Comparable declared in method sort(List,MyComparable) T#2 extends Comparable declared in method compare(T#2,T#2) 1 error 

De este mensaje de error, parece que el comstackdor no puede inferir los argumentos de tipo. Es ese el caso? Si es así, ¿por qué está sucediendo así?

Intenté varias formas, busqué en Internet. Luego encontré este artículo de JavaCodeGeeks , que muestra una forma, así que probé:

 sort(list, <T extends Comparable>(a, b) -> a.compareTo(b)); 

que nuevamente no funciona, al contrario de lo que dice ese artículo que funciona. Podría ser posible que solía funcionar en algunas comstackciones iniciales.

Entonces mi pregunta es: ¿hay alguna forma de crear expresiones lambda para un método genérico? Sin embargo, puedo hacer esto usando una referencia de método, al crear un método:

 public static <T extends Comparable> int compare(T obj1, T obj2) { return obj1.compareTo(obj2); } 

en alguna clase decir SO , y pasarlo como:

 sort(list, SO::compare); 

No puede usar una expresión lambda para una interfaz funcional , si el método en la interfaz funcional tiene parámetros de tipo . Ver la sección §15.27.3 en JLS8 :

Una expresión lambda es compatible […] con un tipo de destino T si T es un tipo de interfaz funcional (§9.8) y la expresión es congruente con el tipo de función de [..] T. [..] Una expresión lambda es congruente con un tipo de función si todos los siguientes son verdaderos:

  • El tipo de función no tiene parámetros de tipo .
  • [..]

Usando la referencia del método, encontré otra forma de pasar el argumento:

 List list = Arrays.asList("a", "b", "c"); sort(list, Comparable::compareTo); 

¿Quieres decir algo como esto ?:

 (T t, S s)->... 

¿De qué tipo es esta lambda? No puede express eso en Java y, por lo tanto, no puede componer esta expresión en una aplicación de función y las expresiones deben poder componerse.

Para que esto sea necesario, necesitarás soporte para los Tipos Rank2 en Java.

Los métodos pueden ser generics, pero por lo tanto no se pueden usar como expresiones. Sin embargo, se pueden reducir a la expresión lambda mediante la especialización de todos los tipos generics necesarios antes de poder pasarlos: ClassName::methodName