Comment surcharger une fonction avec paramètre générique dans JAVA 8?
public class Test<T> { List<T> list = new ArrayList<>(); public int sum(Function<T, Integer> function) { return list.stream().map(function).reduce(Integer::sum).get(); } public double sum(Function<T, Double> function) { return list.stream().map(function).reduce(Double::sum).get(); } }
3 Réponses :
Benji Weber a écrit une fois écrit d'un façon de contourner cela. Ce que vous devez faire est de définir des interfaces fonctionnelles personnalisées qui étendent les types de paramètres:
public class Test<T> { List<T> list = new ArrayList<>(); @FunctionalInterface public int sum(ToIntFunction function) { return list.stream().mapToInt(function).sum(); } public double sum(ToDoubleFunction function) { return list.stream().mapToDouble(function).sum(); } }
Votre suggestion d'utiliser une interface wrapper est bonne mais pas «propre» car test code> doit être modifié à chaque fois qu'une nouvelle opération ou un nouveau type doit être introduit. Avec seulement deux types (entier ou double) et deux opérations (somme et multiplie), vous avez besoin de 4 méthodes. Sans parler des interfaces d'emballage que vous devez créer pour chaque type. C'est une explosion de l'API. +1 pour le lien cependant.
Cela ne fonctionne pas très bien :) Voir pour un exemple similaire Comparateur compareringdouble (todoublefunction) code>,
comparerindinting (TOINTFUNCTION) code> - Les méthodes ont des noms différents, car la surcharge n'est pas une bonne idée.
L'exemple que vous présentez dans votre question n'a rien à voir avec Java 8 et tout ce qui est à faire avec la façon dont les génériques travaillent dans Java. qui étant dit, Srborlongan a déjà fourni un moyen de résoudre le problème. Le problème avec cette solution est que vous devez continuer à modifier votre classe code> de classe code> pour chaque type de fonctionnement (addition, soustraction, etc.) sur différents types (entier, double, etc.). Une solution alternative serait d'utiliser la méthode modifier le test code> Classe de la classe comme suit : p> Créer une sous-classe de code client peut ensuite utiliser le code ci-dessus comme suit: p> L'avantage de l'utilisation de cette approche est que votre fonction
fonction
code>. La règle générale pour la surcharge de la méthode est d'avoir un nombre différent, un type ou une séquence de paramètres. Étant donné que les deux méthodes se transformeront pour prendre un argument code> code>, le compilateur se plaint.
remplacement code> au lieu de
surcharge de la méthode code>: p>
test code> qui ajoutera deux
entier code> s. p>
test code> La classe est en ligne avec le principe code> ouvert sur ouvert (code>. Pour ajouter une nouvelle opération telle que la multiplication, tout ce que vous avez à faire est d'ajouter une nouvelle sous-classe de
test code> et
de remplacement code> de la méthode code> code> pour multiplier deux Nombres. Club cela avec le décorateur motif et vous pouvez même minimiser le nombre de sous-classes que vous avez Pour créer. P>
code> une interface fonctionnelle au lieu d'une classe abstraite) qui dépasse la portée de la question. P> p>
Il est beaucoup plus facile d'utiliser des noms de méthodes différents :) Sumint, Sumdouble Code>
Cela peut être facilement arrangé en faisant des opération code> A
méthode protégée code> dans
test code>, créant un
sumxyz code> méthode dans la sous-classe et Appeler la méthode de remplacement
opération code>. :) Mais comme je l'ai dit, il y a beaucoup de domaines d'amélioration qui dépassent la portée de la réponse.
La solution de @srborlongan ne fonctionnera pas très bien :)
Voir un exemple similaire - comparateur méthodes - La raison est, lorsque vous faites c'est décevant. Dans la phase précédente, Java8 avait un moteur d'inférence plus sophistiqué et règle de gézantique pour les méthodes de surcharge avec des arguments fonctionnels: les arités des interfaces fonctionnelles doivent être différentes, à moins que les deux sont à la fois 0. P > La raison pour laquelle la surcharge avec l'ARITY 0 est correcte est que les expressions Lambda ne seront pas implicites - tous les types d'arguments sont connus (car il n'y a pas d'argument!), nous n'avons pas besoin de Informations contextuelles pour inférer le type Lambda P> compareringdouble (todoublefunction) code>,
comparaison (TOINFONCTION) code>, etc. Les méthodes ont des noms différents, parce que la surcharge n'est pas une bonne idée ici. p>
somme (t -> {...}) code>, le compilateur est incapable de déduire quelle méthode appeler; En fait, il doit résoudre la surcharge de la méthode de la méthode, pour choisir une méthode, avant d'inférer le type de l'expression implicite de la Lambda (basée sur la signature de cette méthode) p>
comparateur code> avait surchargé
comparer () code> méthodes; et
somme (t -> {...}) code> serait correctement déduit également. Malheureusement, ils ont décidé de simplement cela :( et ici nous sommes maintenant. P>
m3( ()-> return new Y() ); // lambda type is ()->Y
m3( ()-> return new B() ); // lambda type is ()->B
Identique à Java 7, 6 et 5: Vous ne pouvez pas. C'est ce que le message vous dit.