8
votes

Méthode générique pour effectuer une opération de réduction des cartes. (Java-8)

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();
    }
}


1 commentaires

Identique à Java 7, 6 et 5: Vous ne pouvez pas. C'est ce que le message vous dit.


3 Réponses :


6
votes

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();
    }
}


2 commentaires

Votre suggestion d'utiliser une interface wrapper est bonne mais pas «propre» car test 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) , comparerindinting (TOINTFUNCTION) - Les méthodes ont des noms différents, car la surcharge n'est pas une bonne idée.



3
votes

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. fonction fonction et fonction fonction passera par Effacement de type Lors de la compilation et sera transformé en fonction . 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 , le compilateur se plaint.

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 de classe pour chaque type de fonctionnement (addition, soustraction, etc.) sur différents types (entier, double, etc.). Une solution alternative serait d'utiliser la méthode remplacement au lieu de surcharge de la méthode :

modifier le test Classe de la classe comme suit : xxx

Créer une sous-classe de test qui ajoutera deux entier s. xxx

code client peut ensuite utiliser le code ci-dessus comme suit: xxx

L'avantage de l'utilisation de cette approche est que votre test La classe est en ligne avec le principe 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 et de remplacement de la méthode 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.

note L'exemple de cette réponse est indicatif. Il y a beaucoup de domaines d'amélioration (tels que faire un test une interface fonctionnelle au lieu d'une classe abstraite) qui dépasse la portée de la question.


2 commentaires

Il est beaucoup plus facile d'utiliser des noms de méthodes différents :) Sumint, Sumdouble


Cela peut être facilement arrangé en faisant des opération A méthode protégée dans test , créant un sumxyz méthode dans la sous-classe et Appeler la méthode de remplacement opération . :) 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.



1
votes

La solution de @srborlongan ne fonctionnera pas très bien :)

Voir un exemple similaire - comparateur méthodes - 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>

La raison est, lorsque vous faites 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>

c'est décevant. Dans la phase précédente, Java8 avait un moteur d'inférence plus sophistiqué et 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>

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 > xxx pré>

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>

m3( ()-> return new Y() );   // lambda type is ()->Y
m3( ()-> return new B() );   // lambda type is ()->B


0 commentaires