Рубрики
Без рубрики

Слияние потоков в Java

Изучите различные способы объединения потоков Java.

Автор оригинала: baeldung.

1. Обзор

В этой краткой статье мы объясним различные способы объединения Java Streams , что не очень интуитивно понятно.

2. Использование простой Java

Класс JDK 8 Stream имеет некоторые полезные статические служебные методы. Давайте подробнее рассмотрим метод concat () .

2.1. Слияние Двух Потоков

Самый простой способ объединить 2 Stream s-использовать статический метод Stream.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. Объединение Нескольких Потоков

Когда нам нужно объединить более 2 потоков, все становится немного сложнее. Одна из возможностей состоит в том, чтобы объединить первые два потока, затем объединить результат со следующим и так далее.

Следующий фрагмент кода показывает это в действии:

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

Как мы видим, этот подход становится неосуществимым для большего количества потоков. Конечно, мы можем создать промежуточные переменные или вспомогательные методы, чтобы сделать его более читаемым, но вот лучший вариант:

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

То, что здесь происходит,:

  • Сначала мы создаем новый Поток , содержащий 4 Потока, в результате чего получается Поток<Поток<Целое число>>
  • Затем мы flatMap() преобразуем это в Поток<Целое число> с помощью функции идентификации

3. Использование Streamyx

Stream Ex -это библиотека Java с открытым исходным кодом, которая расширяет возможности потоков Java 8. Он использует класс StreamEx в качестве улучшения интерфейса Stream JDK.

3.1. Слияние потоков

Библиотека StreamEx позволяет объединять потоки с помощью метода append() instance:

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

Поскольку это метод экземпляра, мы можем легко связать его в цепочку и добавить несколько потоков.

Обратите внимание, что мы также можем создать Список из потока с помощью ToList () , если мы введем переменную результирующего потока в тип StreamEx .

3.2. Объединение Потоков С Помощью prepend()

Streamyx также содержит метод, который добавляет элементы друг перед другом под названием prepend() :

@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. Использование Jooλ

jOOλ – это библиотека, совместимая с JDK 8, которая предоставляет полезные расширения для JDK. Наиболее важная абстракция потока здесь называется Seq . Обратите внимание, что это последовательный и упорядоченный поток, поэтому вызов parallel() не будет иметь никакого эффекта.

4.1. Слияние потоков

Так же, как и библиотека StreamEx, Joopl имеет метод append() :

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

Кроме того, существует удобный метод ToList () , если мы введем переменную resultingSeq в тип jOOλ Seq .

4.2. Объединение Потоков С добавлением()

Как и ожидалось, поскольку существует метод append () , в JOOPL также есть метод prepend() :

@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. Заключение

Мы видели, что объединение потоков относительно просто с помощью JDK 8. Когда нам нужно сделать много слияний, может быть полезно использовать библиотеку StreamEx или Joopl для удобства чтения.

Вы можете найти исходный код на GitHub .