Post

Java 스트림 병합

1. 일반 자바 사용

JDK 8 Stream 클래스에는 몇 가지 유용한 정적 유틸리티 메서드가 있다. concat() 메서드를 확인한다.

1) 두 스트림 병합

Stream 2개를 결합하는 가장 간단한 방법은 정적 Stream.concat() 메서드를 사용하는 것이다.

1
2
3
4
5
6
7
8
9
10
11
@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개 이상의 스트림을 병합해야 하면 상황이 좀 더 복잡해진다. 한 가지 가능성은 처음 두 스트림을 연결한 후 그 결과를 다음 스트림과 연결하는 것이다.

다음 코드에서는 이를 실제로 보여준다.

1
2
3
4
5
6
7
8
9
10
11
12
13
@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()));
}

보시다시피, 이 접근 방식은 더 많은 스트림에서 실행 불가능해진다. 물론 중간 변수나 도우미 메서드를 만들어 더 읽기 쉽게 만들 수 있지만 더 나은 옵션은 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@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()));
}

여기서 일어나는 일은 다음과 같다.

  • 먼저 4개의 스트림을 포함하는 새 스트림을 생성한다. 그 결과 Stream<Stream<Integer>>가 생성된다.

  • 그런 다음 ID 함수를 사용하여 이를 Stream<Integer>flatMap()한다.

2. StreamEx 사용

StreamEx는 Java 8 Streams의 가능성을 확장하는 오픈 소스 Java 라이브러리이다. JDK의 Stream 인터페이스에 대한 향상된 기능으로 StreamEx 클래스를 사용한다.

1) 스트림 병합

StreamEx 라이브러리를 사용하면 append() 인스턴스 메서드를 사용하여 스트림을 병합할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@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()));
}

인스턴스 메서드이므로 쉽게 연결하고 여러 스트림을 추가할 수 있다.

StreamEx 유형에 resultStream 변수를 입력하는 경우 toList()를 사용하여 스트림에서 목록을 생성할 수도 있다.

2) prepend()를 사용하여 스트림 병합

StreamEx에는 요소를 서로 앞에 추가하는 prepend()라는 메서드도 포함되어 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@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()));
}

3. Jooλ 사용

jOOL은 JDK에 유용한 확장을 제공하는 JDK 8 호환 라이브러리이다. 여기서 가장 중요한 스트림 추상화는 Seq이다. 이는 순차적이고 순서가 지정된 스트림이므로 parallel()을 호출해도 아무런 효과가 없다.

1) 스트림 병합

StreamEx 라이브러리와 마찬가지로 jOOλ에도 append() 메소드가 있다.

1
2
3
4
5
6
7
8
9
10
11
12
@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()));
}

또한 jOOλ Seq 유형에 resultingSeq 변수를 입력하면 편리한 toList() 메소드가 있다.

2) prepend()를 사용하여 스트림 병합

예상한 대로, append() 메소드가 존재하므로 jOOλ에도 prepend() 메소드가 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@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()));
}

[출처 및 참고]

This post is licensed under CC BY 4.0 by the author.