Fusion de flux en Java

Fusion de flux en Java

1. Vue d'ensemble

Dans cet article rapide, nous expliquons différentes manières de fusionner JavaStreams - ce qui n'est pas une opération très intuitive.

2. Utilisation de Java brut

La classe JDK 8Stream contient des méthodes utilitaires statiques utiles. Examinons de plus près la méthodeconcat().

2.1. Fusion de deuxStreams

La façon la plus simple de combiner 2Streams est d'utiliser la méthode statiqueStream.concat():

@Test
public void whenMergingStreams_thenResultStreamContainsElementsFromBoth() {
    Stream stream1 = Stream.of(1, 3, 5);
    Stream stream2 = Stream.of(2, 4, 6);

    Stream resultingStream = Stream.concat(stream1, stream2);

    assertEquals(
      Arrays.asList(1, 3, 5, 2, 4, 6),
      resultingStream.collect(Collectors.toList()));
}

2.2. Fusion de plusieursStreams

Lorsque nous devons fusionner plus de 2Streams,, les choses deviennent un peu plus complexes. Une possibilité consiste à concaténer les deux premiers flux, puis à concaténer le résultat avec le suivant, etc.

L'extrait de code suivant montre ceci en action:

@Test
public void given3Streams_whenMerged_thenResultStreamContainsAllElements() {
    Stream stream1 = Stream.of(1, 3, 5);
    Stream stream2 = Stream.of(2, 4, 6);
    Stream stream3 = Stream.of(18, 15, 36);

    Stream resultingStream = Stream.concat(
      Stream.concat(stream1, stream2), stream3);

    assertEquals(
      Arrays.asList(1, 3, 5, 2, 4, 6, 18, 15, 36),
      resultingStream.collect(Collectors.toList()));
}

Comme on peut le constater, cette approche devient irréalisable pour davantage de flux. Bien sûr, nous pouvons créer des variables intermédiaires ou des méthodes auxiliaires pour le rendre plus lisible, mais voici une meilleure option:

@Test
public void given4Streams_whenMerged_thenResultStreamContainsAllElements() {
    Stream stream1 = Stream.of(1, 3, 5);
    Stream stream2 = Stream.of(2, 4, 6);
    Stream stream3 = Stream.of(18, 15, 36);
    Stream stream4 = Stream.of(99);

    Stream resultingStream = Stream.of(
      stream1, stream2, stream3, stream4)
      .flatMap(i -> i);

    assertEquals(
      Arrays.asList(1, 3, 5, 2, 4, 6, 18, 15, 36, 99),
      resultingStream.collect(Collectors.toList()));
}

Ce qui se passe ici est:

  • On crée d'abord un nouveauStream contenant les 4Streams, qui se traduit par unStream<Stream<Integer>>

  • Ensuite, nousflatMap() ceci dans unStream<Integer> en utilisant la fonction d'identité

3. Utilisation de StreamEx

StreamEx est une bibliothèque Java open source qui étend les possibilités de Java 8 Streams. Il utilise la classeStreamEx comme une amélioration de l’interfaceStream du JDK.

3.1. Fusion deStreams

La bibliothèque StreamEx nous permet de fusionner des flux en utilisant la méthode d'instanceappend():

@Test
public void given4Streams_whenMerged_thenResultStreamContainsAllElements() {
    Stream stream1 = Stream.of(1, 3, 5);
    Stream stream2 = Stream.of(2, 4, 6);
    Stream stream3 = Stream.of(18, 15, 36);
    Stream stream4 = Stream.of(99);

    Stream resultingStream = StreamEx.of(stream1)
      .append(stream2)
      .append(stream3)
      .append(stream4);

    assertEquals(
      Arrays.asList(1, 3, 5, 2, 4, 6, 18, 15, 36, 99),
      resultingStream.collect(Collectors.toList()));
}

Puisqu'il s'agit d'une méthode d'instance, nous pouvons facilement la chaîner et ajouter plusieurs flux.

Notez que nous pourrions également créer unList hors du flux en utilisanttoList() si nous tapons la variableresultingStream au typeStreamEx.

3.2. Fusion de flux à l'aide deprepend()

StreamEx contient également une méthode qui ajoute des éléments les uns avant les autres appelésprepend():

@Test
public void given3Streams_whenPrepended_thenResultStreamContainsAllElements() {
    Stream stream1 = Stream.of("foo", "bar");
    Stream openingBracketStream = Stream.of("[");
    Stream closingBracketStream = Stream.of("]");

    Stream resultingStream = StreamEx.of(stream1)
      .append(closingBracketStream)
      .prepend(openingBracketStream);

    assertEquals(
      Arrays.asList("[", "foo", "bar", "]"),
      resultingStream.collect(Collectors.toList()));
}

4. Utilisation de Jooλ

jOOλ est une bibliothèque compatible JDK 8 qui fournit des extensions utiles au JDK. L'abstraction de flux la plus importante ici est appeléeSeq. Notez qu'il s'agit d'un flux séquentiel et ordonné, donc appelerparallel() n'aura aucun effet.

4.1. Fusion de flux

Tout comme la bibliothèque StreamEx, jOOλ a une méthodeappend():

@Test
public void given2Streams_whenMerged_thenResultStreamContainsAllElements() {
    Stream seq1 = Stream.of(1, 3, 5);
    Stream seq2 = Stream.of(2, 4, 6);

    Stream resultingSeq = Seq.ofType(seq1, Integer.class)
      .append(seq2);

    assertEquals(
      Arrays.asList(1, 3, 5, 2, 4, 6),
      resultingSeq.collect(Collectors.toList()));
}

De plus, il existe une méthode pratiquetoList() si nous tapons la variableresultingSeq avec le type jOOλSeq.

4.2. Fusion de flux avecprepend()

Comme prévu, puisqu'il existe une méthodeappend(), il existe également une méthodeprepend() dans jOOλ:

@Test
public void given3Streams_whenPrepending_thenResultStreamContainsAllElements() {
    Stream seq = Stream.of("foo", "bar");
    Stream openingBracketSeq = Stream.of("[");
    Stream closingBracketSeq = Stream.of("]");

    Stream resultingStream = Seq.ofType(seq, String.class)
      .append(closingBracketSeq)
      .prepend(openingBracketSeq);

    Assert.assertEquals(
      Arrays.asList("[", "foo", "bar", "]"),
      resultingStream.collect(Collectors.toList()));
}

5. Conclusion

Nous avons vu que la fusion de flux est relativement simple avec JDK 8. Lorsque nous avons besoin de faire beaucoup de fusion, il peut être avantageux d’utiliser la bibliothèque StreamEx ou jOOλ par souci de lisibilité.

Vous pouvez trouver le code sourceover on GitHub.