2017-09-18 6 views
1

J'aime les nouvelles méthodes d'usine statiques de Comparator, car ils permettent de mettre en œuvre Comparateurs de manière très concise et moins sujette aux erreurs.Java 8: la mise en œuvre Comparable

Mais quelle est la méthode recommandée pour mettre en œuvre Comparable? Devrions-nous utiliser des comparateurs dans la mise en œuvre comparable?

public MyClass implements Comparable<MyClass>{ 
... 
    public int compareTo(MyClass other){ 
     Comparator<MyClass> naturalOrderComparator = 
      Comparator.comparing(MyClass::getFoo) 
         .thenComparing(MyClass::getBar); 
     return naturalOrderComparator.compare(this, other); 
    } 
} 

ou même utiliser un comparateur statique pour réduire un grand nombre de création d'objets lors du tri des collections énormes:

public MyClass implements Comparable<MyClass>{ 
    private static final Comparator<MyClass> NATURAL_ORDER_COMPARATOR =  
     Comparator.comparing(MyClass::getFoo) 
        .thenComparing(MyClass::getBar); 

    ... 

    public int compareTo(MyClass other){ 
     return NATURAL_ORDER_COMPARATOR.compare(this, other); 
    } 
} 

Ou est-il un autre moyen recommandé de mettre en œuvre Comparable Java SE 8?

+0

Ce sont de minuscules méthodes pratiques que vous pouvez facilement implémenter vous-même - l'appel de la statique Comparator n'est pas plus court. Pour les classes qui ont besoin de méthodes de comparaison intégrées, cela est inutile en termes de lisibilité et de brièveté, sans parler des performances. Vous pouvez consulter la source http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/util/Comparator.java#Comparator.comparingInt%28java.util. function.ToIntFunction% 29 – pvg

+0

@pvg Quel est l'avantage d'implémenter moi-même des méthodes utilitaires en utilisant les méthodes statiques de Comparator? Pouvez-vous faire un échantillon qui est similaire concis? – Puce

+3

Je recommande fortement votre deuxième option. L'écriture de ces choses vous-même est susceptible d'être plus sujette aux erreurs. –

Répondre

2

Votre propre option 2 est certainement le meilleur moyen disponible actuellement. Il évite l'allocation, il se lit plutôt bien - surtout si vous mettez la constante statique à côté de la méthode compareTo. Les nouvelles méthodes d'usine Comparator.comparing en Java 8 sont très faciles à lire, et encore mieux, difficiles à bousiller - il y a beaucoup, beaucoup de façons d'écrire des comparaisons incorrectement à la main, plus que je ne veux me souvenir, et le Les méthodes d'usine sont immunisées contre la plupart d'entre elles. Même s'il est un peu bizarre de les utiliser pour écrire une méthode compareTo au lieu d'un objet Comparator, c'est encore mieux que les alternatives.

+2

Il n'y a que deux choses à prendre en compte. 1.) les comparateurs produits en usine ne vous protègent pas de la création d'une logique qui est incompatible avec les égaux, par conséquent, vous devez toujours vous en soucier. 2.) vous devez résister à la tentation de créer des comparateurs null-safe. Alors que les comparateurs peuvent fournir une logique formellement correcte pour les valeurs null, les comparables ne peuvent pas, comme le contrat requiert une symétrie, donc 'compareInstance.compareTo (null)' doit lancer une exception, comme '(null) .compareTo (comparableInstance)' aurait. – Holger

1

Pré-Java-8 la meilleure pratique générale consistait à utiliser GuavaComparisonChain et Ordering utilitaires. Ils abstraire les détails encombrants et faciles à obtenir-faux de mettre en œuvre correctement une méthode .compareTo()/.compare(), et vous permettent de composer une séquence lisible par l'homme d'étapes pour définir comment les objets doivent être comparés. Ordering implémente Comparator, mais il n'y aurait rien de mal à la définition d'un Ordering et en invoquant dans une méthode de .compareTo()Comparable.

Notez que Ordering est décrit comme obsolète grâce aux ajouts à la JDK Java 8:

Si vous utilisez Java 8, cette classe est désormais obsolète .... La plupart de ses fonctionnalités est maintenant fourni par Stream et par Comparator lui-même, et le reste peut maintenant être trouvé en tant que méthodes statiques dans notre nouvelle classe Comparators.