3
votes

L'utilisation de BiFunction à la place d'un comparateur ne fonctionne pas

Lors de l'initialisation de collections comme TreeMap , TreeSet , etc. Nous pouvons ajouter notre comparateur personnalisé. Le code ressemble à quelque chose comme:

BiFunction<Integer, Integer, Integer> myComparator = (x,y) -> x-y;
Map<Integer, String> map3 = new TreeMap<>(myComparator);

Maintenant, nous pouvons faire remplacer cette implémentation anonyme par une expression lambda. Le code ressemblerait à ceci:

Map<Integer, String> map2 = new TreeMap<>((x,y) -> x-y);

Java-8 vous permet de stocker des expressions lambda dans une variable via interfaces fonctionnelles . Donc, j'ai modifié le code ci-dessus comme suit:

Map<Integer, String> map1 = new TreeMap<>(new Comparator<Integer>() {
    public int compare(Integer x, Integer y) {
        return x-y;
    }
});

Mais cette dernière tentative n'a pas fonctionné! Il a donné l'erreur suivante:

Impossible de déduire les arguments de type pour TreeMap

Pourquoi n'a-t-il pas réussi à résoudre les types dans le dernier exemple?

Remarque: Pour confirmer qu'il ne s'agit pas d'un bogue IDE, j'ai effectué une compilation brute en utilisant javac code> et il a toujours donné la même erreur.


9 commentaires

Ne pourriez-vous pas déclarer votre fonction lambda comme Comparator myComparator = (x, y) -> x-y; au lieu de BiFunction ? Puisque Comparator est explicitement le type requis par le constructeur TreeMap .


J'obtiens un "impossible de résoudre le constructeur ...." .


@ luk2302, quelle version de java utilisez-vous?


@khelwood qui fonctionne !!. Mais ne résout malheureusement pas la question.


@AdityaGupta 1.8.0_131 - "aucun constructeur approprié trouvé pour ..." est la sortie réelle, l'autre est généré par IntelliJ semble-t-il.


Savez-vous ce qu'est une «interface fonctionnelle»? Ce n'est pas une interface requise pour être dans le package java.util.function . Comparator est déjà une interface fonctionnelle. C'est pourquoi vous pouvez utiliser une expression lambda lorsqu'un Comparator est requis, comme avec new TreeMap <> ((x, y) -> x-y) . Qu'espérez-vous gagner en utilisant BiFunction au lieu de Comparator ? De plus, n’utilisez pas moins comme fonction de comparaison . Les moins peuvent déborder. Et de toute façon, Comparator.naturalOrder () est déjà adapté à cette tâche. (Ou créez simplement la TreeMap sans comparateur)


@ luk2302 Essayez ceci


@Holger, je testais des expressions lambda qui pourraient être utilisées comme comparateurs lors de l'exécution. Comparator.naturalOrder () est un bon conseil, mais toutes les implémentations ne seront pas disponibles dans Comparator .


Quelle que soit la logique que vous implémentez, évitez d'utiliser moins. Il y a Integer.compare (int, int) qui fait la bonne chose, mais généralement, lorsque vous finissez par comparer deux valeurs int , vous pouvez utiliser l'un ou l'autre Comparator. naturalOrder () , Comparator.reverseOrder () , Comparator.comparingInt (…) , ou une combinaison de ceux-ci.


3 Réponses :


7
votes

Bien que l'expression lambda semble identique, le BiFunction n'est pas le Comparator donc vous ne pouvez pas les échanger.

Comparator<Integer> comparator = new Comparator<Integer>() {
    @Override
    public int compare(Integer x, Integer y) {
        return x - y;
    }
};

BiFunction<Integer, Integer, Integer> biFun = new BiFunction<Integer, Integer, Integer>() {
    @Override
    public Integer apply(final Integer x, final Integer y) {
        return x - y;
    }
};

Examinons plus en détail ces interfaces et implémentons-les en utilisant une classe anonyme:

Comparator<Integer> comparator = (x,y) -> x - y;
Map<Integer, String> map3 = new TreeMap<>(comparator);

La différence est aussi le nom de la méthode. TreeMap attend Comparateur dans son constructeur car son implémentation interne appellera compare selon le contrat avec Comparateur .

Au fait, le BinaryOperator donne également la même expression lambda.


0 commentaires

1
votes

C'est simplement parce que le constructeur TreeMap attend un Comparator plutôt qu'une BiFunction .

En écrivant BiFunction myComparator = ... , vous dites explicitement au compilateur que la variable est de ce type. Cela empêche le compilateur de déduire le type requis pour le constructeur TreeMap . Puisque BiFunction n'est pas un comparateur , ni une sous-classe de celui-ci, le compilateur ne le permet pas.


0 commentaires

0
votes

Parce qu'il attend le comparateur et que vous avez fourni la fonction BiFunction. Depuis Oracle Docs:

@FunctionalInterface
public interface Comparator<T>

Une fonction de comparaison, qui impose un ordre total sur une collection d'objets. Les comparateurs peuvent être passés à une méthode de tri (telle que Collections.sort ou Arrays.sort) pour permettre un contrôle précis sur l'ordre de tri. Les comparateurs peuvent également être utilisés pour contrôler l'ordre de certaines structures de données (telles que des ensembles triés ou des cartes triées), ou pour fournir un ordre pour des collections d'objets qui n'ont pas un ordre naturel.


0 commentaires