Lors de la validation d'identifiants multiples provenant d'une collection d'objets en Java 8, il est courant d'utiliser l'API Stream pour extraire et traiter les données. Par exemple, considérons une classe Employe avec trois identifianst : refA, refB et refC. L'objectif est de collecter tous ces identifiants pour une vérification ultérieure.
public class Employe {
private String nom;
private String refA;
private String refB;
private String refC;
// Getters et setters
}
En général, l'extraction d'un seul champ s'effectue avec map :
List<String> refsA = listeEmployes.stream()
.map(Employe::getRefA)
.collect(Collectors.toList());
Pour récupérer plusieurs champs, on peut recourir à Stream.concat pour combiner des flux individuels.
Apprcohe avec Stream.concat
La méthode statique concat de Stream assemble deux flux en un seul. Pour trois identifiants, cela requiert deux fusions successives :
Stream<String> flux1 = listeEmployes.stream()
.map(Employe::getRefA);
Stream<String> flux2 = listeEmployes.stream()
.map(Employe::getRefB);
Stream<String> fluxCombine = Stream.concat(flux1, flux2);
List<String> toutesRefs = Stream.concat(fluxCombine, listeEmployes.stream().map(Employe::getRefC))
.filter(Objects::nonNull)
.collect(Collectors.toList());
Cette méthode manque de concision lorsque le nombre de champs augmente. Une solution plus élégante repose sur flatMap.
Application de flatMap
La méthode flatMap possède la signature suivante :
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
Elle convertit chaque élément d'un flux en un autre flux, puis fusionne tous les flux résultants en un flux unique. Contrairement à map, flatMap renvoie un flux plutôt qu'une valeur simple.
En utilisant Stream.of pour créer un flux de flux, on peut appliquer flatMap pour les aplatir :
List<String> toutesRefs = Stream.of(
listeEmployes.stream().map(Employe::getRefA),
listeEmployes.stream().map(Employe::getRefB),
listeEmployes.stream().map(Employe::getRefC))
.flatMap(fluxCourant -> fluxCourant)
.filter(Objects::nonNull)
.collect(Collectors.toList());
Ici, Stream.of(flux1, flux2, flux3) produit un flux de type Stream<Stream<String>>. L'expression lambda dans flatMap retourne chaque flux tel quel, permettant ainsi de les combiner en un seul Stream<String>.
Cas pratique complémentaire
Pour approfondir, imaginons un tableau de chaînes séparées par des points-virgules, tel que {"p,q;r,s", "s,t;u,v"}. On souhaite fusionner tous les éléments dans une liste unique, sans doublons, en gérant le séparateur multiple.
public static void main(String[] args) {
String[] donnees = {"p,q;r,s", "s,t;u,v"};
List<String> elementsFusionnes = Arrays.stream(donnees)
.map(entree -> entree.split("[,;]"))
.flatMap(Arrays::stream)
.distinct()
.collect(Collectors.toList());
System.out.println(elementsFusionnes);
}
Dans cet exemple, map transforme chaque entrée en un tableau de sous-chaînes à l'aide d'une expression régulière, et flatMap aplatit ces tableaux en un flux de chaînes, facilitant ainsi les opérations de traitement de flux.