Accueil / Articles PiApplications. / La plate-forme Java / Le langage

Les collecteurs de streams java.

Un collecteur permet (interface Collector) est un objet qui effectue une opération de réduction sur un flux d'éléments vers un conteneur d'objets modifiables après d'éventuelles manipulations sur chacun des éléments du flux. Ces conteneurs peuvent être des objets de classe List, Map, String etc.

Un collecteur est invoqué par l'opération terminale collect. La classe utilitaire Collectors contient de nombreuses méthodes statiques qui permettent de créer un collecteur.

La classe Collectors.

La classe Collectors est la classe qui fournit les collecteurs indispensable à la méthode collect. Plusieurs méthodes de cette classe disposent de prototypes permettant l'emploi de streams "amont". Ces streams "amont" permettent l'utilisation d'un second stream pour être utilisé avec les méthodes collectingAndThen, groupingBy, groupingByConcurrent, mapping et partitioningBy.

La construction de listes.

Des méthodes simples de la classe Collectors permettent le transfert directs d'éléments dans un collection :

  1.  toCollection(Supplier sppFactory);
  2. toList ;
  3. toSet.

La méthode toCollection permet de placer les éléments de la collection dans l'ordre du parcours tandis que la méthode toSet permet l'ajout des éléments dans un objet Set en éliminant les doublons.

La construction de cartes.

La méthode toMap(Function fncKeyMapper, Function fncValueMapper) permet la création d'un objet de classe Map. Les paramètres permettent d'identifier la clef et la valeur à placer dans la "carte". Lorsque la clef ou la valeur doivent être extraites ou construites à partir du contenu de l'élément courant du parcours, ce dernier est retourné par la méthode statique Function.Identity :
Map<Student, Double> map = stsStudents.stream().collect(toMap(Functions.identity(), std -> getScore(std)));.

Une des difficulté des objet de classe Map est la gestion des clefs dupliquées. En général, lorsqu'un stream contient des éléments qui fournissent des clefs dupliquées, on ne souhaite pas créer une entrée dans la carte (qui détruirait la précédebte) mais plutôt fusionner le nouvel élément avec celui existant déjà dans la carte. C'est exactement ce que permet la méthode toMap(Funtion fncKeyMapper, Function fncValueMapper, BinaryOperator bopMerger).

Par exemple Mapmap = lstPeople.stream().collect(toMap(Person::getAddress, Person::getName, (prsL, prsR) -> prsL + "," + prsR));permet de créer une carte de toutes les personnes qui ont la même adresse. La clef est l'adresse tandis que la valeur est a liste des noms de personnes avec une virgule comme séparateur.

Il est également possible de créer une carte de listes (la valeur de chaque entrée d'un objet de classe Map est une liste). Ceci est réalisé grâce à la méthode groupingBy(Function fnc). Le résultat est de classe Map<K, List<V>>.

La méthode groupingBy peut également être utilisée avec un stream "amont" : groupingBy(Function fnc, Collector cll).  Le stream "amont" effectue une réduction sur chaque élément du flux puis chaque résultat de cette réduction est transmis au flux appelant. Voyons cela sur un exemple :

Map map = lstWords.stream().groupingBy(String::length, counting());

Chaque élément du flux appelant est ici un mot. (objet de classe String). Le flux amont compte le nombre de mots de cette longueur dans le flux appelant et retourne le résultat au flux appelant qui le stocke alors en tant que valeur à associée à la clef qui est la longueur du mot courant dans le flux. En d'autres termes, le collecteur retourne ici la liste des longueurs de mots et pour chaque longueur le nombre de mots correspondant.

Une autre méthode pratique de la classe Collectors est la concaténation de chaînes via la méthode joining. Une version de cette méthode permet d'ajouter un séparateur comme dans cet exemple : collect(Collectors.joining(",")); (création d'une fichier CSV par exemple). Il est même possible d'ajouter un préfixe et un suffixe à la concaténation : collect(Collectors.joining(delimiter, prefix, suffix));.

Les collecteurs numériques.

Certaines méthodes de la classe Collectors permettent le collationnement numérique :

Bien entendu le même jeu de méthodes existe pour les types primitifs long et double.

Les collecteurs particuliers.

Il existe encore d'autres sortes de méthodes produisant des collecteurs dont :

Bref, pas toujours simple à appréhender mais très puissant ! On pourrait résumer cela en écrivant "la simplicité et la puissance SQL sans  le brouillard de l'indétermination au regard de la question posée".

(c) PiApplications 2016