mars
2014
L’API de Collections de Java apporte la notion d’ordre des objets, soit via l’interface Comparable<T> qui définit l’ordre naturel, soit via l’interface Comparator<T> qui permet de définir des règles d’ordonnancements diverses.
La majeur partie des classes et méthodes qui nécessite un ordonnancement utilisent donc un Comparator<T>.
Bien que sur le principe cela ne soit pas très complexe en soit, cela restait relativement verbeux à écrire et source de bug ou comportement étrange en cas de petite erreur…
Java 8 va revisiter tout cela, et il y a de forte chance que vous n’ayez plus à écrire le Comparator par vous-même…
Imaginons une classe « Car« , représentant une voiture et ses différentes caractéristiques avec leurs getters (getManufacturer(), getModel(), getYear(), getHorsepower(), …)
L’implémentation d’un Comparator sur ces 4 critères ressemblerait à ceci :
@Override
public int compare(Car c1, Car c2) {
int diff = c1.getManufacturer().compareTo(c2.getManufacturer());
if (diff != 0) {
return diff;
}
diff = c1.getModel().compareTo(c2.getModel());
if (diff != 0) {
return diff;
}
diff = Integer.compare(c1.getYear(), c2.getYear());
if (diff != 0) {
return diff;
}
diff = Integer.compare(c1.getHorsepower(), c2.getHorsepower());
return diff;
}
};
Ce n’est pas bien méchant en soit… mais c’est juste une comparaison basé sur 4 champs.
Cela peut vite devenir plus long et barbant, avec du code répétitif un peu lourdingue.
Heureusement, à partir de Java 8 l’interface Comparator intègrera une méthode static comparing() permettant de créer un comparateur basé sur un champ, en lui passant une expression lambda permettant d’extraire le champ à comparer.
Par exemple pour créer un Comparator basé sur le modèle de voiture on pourra utiliser directement :
Toutefois ce genre d’expression lambda pouvant être remplacée par une référence de méthode, il est plus simple et plus lisible d’utiliser cette forme :
On obtient ainsi un Comparator qui se basera sur la valeur de retour de getModel() pour ordonner les éléments.
Mais ce ne s’arrête pas là, les Comparators s’enrichissent également de nouvelles méthodes d’instances via les méthodes par défaut. On dispose ainsi en particulier de méthode thenComparing() permettant d’enchainer avec un autre comparateur.
On peut ainsi réécrire notre comparateur initial en quelques lignes :
.thenComparing(Car::getModel)
.thenComparingInt(Car::getYear)
.thenComparingInt(Car::getHorsepower);
On peut également affecter un Comparateur à chaque champs, dans le cas où il ne serait pas « Comparable » ou que l’on souhaiterait utiliser un autre ordre de trie :
.thenComparing(Car::getModel, String::compareToIgnoreCase)
// Comparaison selon le modèle, selon les règles françaises :
.thenComparing(Car::getModel, Collator.getInstance(Locale.FRANCE))
// Comparaison selon le modèle, mais en ordre inverse
.thenComparing(Car::getModel, Comparator.reverseOrder())
Bref de quoi traiter une grande majorité de cas facilement et rapidement !
Tutoriels
Discussions
- Définition exacte de @Override
- Classes, méthodes private
- [REFLEXION] Connaitre toutes les classes qui implémentent une interface
- Difference de performances Unix/Windows d'un programme?
- [ fuite ] memoire
- Possibilité d'accéder au type générique en runtime
- Recuperation du nom des parametres
- L'apparition du mot-clé const est-il prévu dans une version à venir du JDK?
- jre 1.5, tomcat 6.0 et multi processeurs