Supposons que j'ai une interface générique:
interface MyComparable<T extends Comparable<T>> {
public int compare(T obj1, T obj2);
}
Et une méthode sort
:
public static <T extends Comparable<T>>
void sort(List<T> list, MyComparable<T> comp) {
// sort the list
}
Je peux invoquer cette méthode et passer une expression lambda comme argument:
List<String> list = Arrays.asList("a", "b", "c");
sort(list, (a, b) -> a.compareTo(b));
Cela fonctionnera très bien.
Mais maintenant, si je rends l'interface non générique et la méthode générique:
interface MyComparable {
public <T extends Comparable<T>> int compare(T obj1, T obj2);
}
public static <T extends Comparable<T>>
void sort(List<T> list, MyComparable comp) {
}
Et puis invoquez ceci comme:
List<String> list = Arrays.asList("a", "b", "c");
sort(list, (a, b) -> a.compareTo(b));
Il ne compile pas. Il montre une erreur à l'expression lambda en disant:
"La méthode cible est générique"
OK, lorsque je l'ai compilé en utilisant javac
, il affiche l'erreur suivante:
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,T#2)int in interface MyComparable is generic)
where T#1,T#2 are type-variables:
T#1 extends Comparable<T#1> declared in method <T#1>sort(List<T#1>,MyComparable)
T#2 extends Comparable<T#2> declared in method <T#2>compare(T#2,T#2)
1 error
À partir de ce message d'erreur, il semble que le compilateur ne soit pas en mesure de déduire les arguments de type. Est-ce le cas? Si oui, pourquoi cela se passe-t-il ainsi?
J'ai essayé différentes méthodes, j'ai cherché sur Internet. Ensuite, j'ai trouvé cet article JavaCodeGeeks , qui montre un moyen, alors j'ai essayé:
sort(list, <T extends Comparable<T>>(a, b) -> a.compareTo(b));
qui encore une fois ne fonctionne pas, contrairement à ce que cet article prétend que cela fonctionne. Peut-être qu'il fonctionnait dans certaines versions initiales.
Ma question est donc la suivante: existe-t-il un moyen de créer une expression lambda pour une méthode générique? Je peux le faire en utilisant une référence de méthode, en créant une méthode:
public static <T extends Comparable<T>> int compare(T obj1, T obj2) {
return obj1.compareTo(obj2);
}
dans une classe, dites SO
et passez-le comme:
sort(list, SO::compare);
En utilisant la référence de méthode, j'ai trouvé un autre moyen de transmettre l'argument:
la source
Indiquez simplement au compilateur la version appropriée du comparateur générique avec
(Comparator<String>)
Donc la réponse sera
sort(list, (Comparator<String>)(a, b) -> a.compareTo(b));
la source
incompatible types: java.util.Comparator<java.lang.String> cannot be converted to MyComparable
etMyComparable
n'est pas générique (pas de type) donc(MyComparable<String>)
ne fonctionnerait pas non plusCompartor
?Tu veux dire quelque chose comme ca?:
De quel type est ce lambda? Vous ne pouvez pas exprimer cela en Java et ne pouvez donc pas composer cette expression dans une application de fonction et les expressions doivent être composables.
Pour que cela soit du travail, vous aurez besoin de la prise en charge des types Rank2 en Java.
Les méthodes sont autorisées à être génériques, mais vous ne pouvez donc pas les utiliser comme expressions. Ils peuvent cependant être réduits à l'expression lambda en spécialisant tous les types génériques nécessaires avant de pouvoir les transmettre:
ClassName::<TypeName>methodName
la source
"Of what type is this lambda? You couldn't express that in Java..."
Le type serait déduit à l'aide du contexte, comme avec n'importe quel autre lambda. Le type d'un lambda n'est pas explicitement exprimé dans le lambda lui-même.