web-dev-qa-db-fra.com

Tri par propriété dans le flux Java 8

Oh, ces délicats Java 8 flux avec lambdas. Ils sont très puissants, mais les subtilités prennent un peu pour envelopper son en-tête autour de tout cela.

Disons que j'ai un type User avec une propriété User.getName(). Disons que j'ai une carte de ces utilisateurs Map<String, User> Associés aux noms (noms d'utilisateur de connexion, par exemple). Disons en outre que j'ai une instance d'un comparateur UserNameComparator.INSTANCE Pour trier les noms d'utilisateurs (peut-être avec des collateurs sophistiqués et autres).

Alors, comment puis-je obtenir une liste des utilisateurs sur la carte, triés par nom d'utilisateur? Je peux ignorer les clés de carte et faire ceci:

return userMap.values()
    .stream()
    .sorted((u1, u2) -> {
      return UserNameComparator.INSTANCE.compare(u1.getName(), u2.getName());
    })
    .collect(Collectors.toList());

Mais cette ligne où je dois extraire le nom pour utiliser le UserNameComparator.INSTANCE Semble être trop de travail manuel. Existe-t-il un moyen de fournir simplement User::getName En tant que fonction de mappage, juste pour le tri, tout en récupérant les instances User dans la liste collectée?

Bonus: que se passe-t-il si la chose sur laquelle je veux trier a deux niveaux de profondeur, comme User.getProfile().getUsername()?

39
Garret Wilson

Ce que vous voulez, c'est Comparator#comparing :

userMap.values().stream()
    .sorted(Comparator.comparing(User::getName, UserNameComparator.INSTANCE))
    .collect(Collectors.toList());

Pour la deuxième partie de votre question, vous utiliseriez simplement

Comparator.comparing(
    u->u.getProfile().getUsername(), 
    UserNameComparator.INSTANCE
)
70
Misha