Merging Streams in Java – 在Java中合并流

最后修改: 2017年 6月 6日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this quick article, we explain different ways of merging Java Streams – which is not a very intuitive operation.

在这篇快速文章中,我们将解释合并Java Streams的不同方法–这并不是一个非常直观的操作。

2. Using Plain Java

2.使用普通的Java

The JDK 8 Stream class has some useful static utility methods. Let’s take a closer look at the concat() method.

JDK 8的Stream类有一些有用的静态实用方法。让我们仔细看看concat()方法。

2.1. Merging Two Streams

2.1.合并两个

The simplest way to combine 2 Streams is to use the static Stream.concat() method:

合并2个Stream的最简单方法是使用静态的Stream.concat()方法。

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

    Stream<Integer> resultingStream = Stream.concat(stream1, stream2);

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

2.2. Merging Multiple Streams

2.2.合并多个s

When we need to merge more than 2 Streams, things become a bit more complex. One possibility is to concatenate the first two streams, then concatenate the result with the next one and so on.

当我们需要合并2个以上的流时,事情变得有点复杂了。一种可能性是将前两个流串联起来,然后将结果与下一个流串联起来,如此反复。

The next code snippet shows this in action:

下一个代码片断显示了这一做法的效果。

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

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

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

As we can see, this approach becomes unfeasible for more streams. Of course, we can create intermediate variables or helper methods to make it more readable, but here is a better option:

我们可以看到,这种方法对于更多的流来说变得不可行。当然,我们可以创建中间变量或辅助方法,使其更具有可读性,但这里有一个更好的选择。

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

    Stream<Integer> 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()));
}

What happens here is:

这里发生的事情是。

  • We first create a new Stream containing the 4 Streams, which results in a Stream<Stream<Integer>>
  • Then we flatMap() this into a Stream<Integer> using the identity function

3. Using StreamEx

3.使用StreamEx

StreamEx is an open-source Java library that extends possibilities of Java 8 Streams. It uses the StreamEx class as an enhancement to the JDK’s Stream interface.

StreamEx是一个开源的Java库,扩展了Java 8 Streams的可能性。它使用StreamEx类作为对JDK的Stream接口的增强。

3.1. Merging Streams

3.1.合并s

The StreamEx library allows us to merge streams using the append() instance method:

StreamEx库允许我们使用append()实例方法来合并流。

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

    Stream<Integer> 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()));
}

Since it is an instance method, we can easily chain it and append multiple streams.

由于它是一个实例方法,我们可以很容易地把它连锁起来,追加多个流。

Note that we could also create a List out of the stream by using toList() if we type the resultingStream variable to the StreamEx type.

请注意,如果我们将resultingStream变量打成StreamEx类型,我们也可以通过使用toList()从流中创建一个List

3.2. Merging Streams Using prepend()

3.2.使用prepend()合并流

StreamEx also contains a method that adds elements before one another called prepend():

StreamEx还包含一个方法,该方法将元素添加到彼此之前,称为prepend()

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

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

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

4. Using Jooλ

4.使用Jooλ

jOOλ is a JDK 8 compatible library that provides useful extensions to the JDK. The most important stream abstraction here is called Seq. Note that this is a sequential and ordered stream, so calling parallel() will have no effect.

jOOλ是一个与JDK 8兼容的库,为JDK提供有用的扩展。这里最重要的流抽象被称为Seq。请注意,这是一个连续的、有序的流,所以调用parallel()不会有任何效果。

4.1. Merging Streams

4.1.合并数据流

Just like the StreamEx library, jOOλ has an append() method:

就像StreamEx库一样,jOOλ有一个append()方法。

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

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

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

Also, there is a convenience toList() method if we type the resultingSeq variable to the jOOλ Seq type.

另外,如果我们将resultingSeq变量输入到jOOλ Seq类型中,有一个方便的toList()方法。

4.2. Merging Streams With prepend()

4.2.用prepend()合并流

As expected, since an append() method exists, there is also a prepend() method in jOOλ:

正如预期的那样,由于存在一个append()方法,在jOOλ中也存在一个prepend()方法。

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

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

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

5. Conclusion

5.结论

We saw that merging streams is relatively straightforward using JDK 8. When we need to do a lot of merging, it might be beneficial to use the StreamEx or jOOλ library for the sake of readability.

我们看到,使用JDK 8合并流是比较直接的。当我们需要进行大量的合并时,出于可读性的考虑,使用StreamEx或jOOλ库可能是有益的。

You can find the source code over on GitHub.

你可以在GitHub上找到源代码over