이 포스팅의 코드 및 정보들은 강의를 들으며 정리한 내용을 토대로 작성한 것입니다.
Sequence of Elements supporting sequential and parallel aggregate operations
연속된 데이터를 처리하는 operation들의 모임/모음이다. 그 자체가 데이터이거나, 데이터를 담고 있는 저장소 자체를 이야기 하는 건 아니다.
stream은 Collection에 데이터를 가지고 있는 것을 소스로 사용해서 처리를 하는 것이다.
예시로, sports의 목록을 ArrayList로 추가하고 이를 stream()으로 연동시켜보겠다. 현재는 stream()만 걸어놨지 아무 일도 일어나지 않은 상태이다. 여기에 다양한 operator를 추가할 수 있다.
위 사진처럼 sports.stream().map(String::toUpperCase);
의 결과(반환 타입은)는 또 다른 Stream이 된다. stream으로 전달받은 데이터 자체를 대문자로 바꾸는 게 아니다.
stringStream 안에 있는 데이터들은 그대로 소문자로 남아있다.
출력해보면 대문자로 바뀌지 않은 것을 알 수 있다.
실시간으로 들어오는 것처럼 stream에 데이터가 무제한으로 넘어올 수 있다. 그때는 어떤 것을 단축시키는, 제한하는 Short Circuit이라는 메서드를 활용할 수 있다.
stream에다가 줄 수 있는 여러 메서드들이 있는데, 이를 중계 operator
, terminal operator
로 나눌 수 있다.
lazy하다는 것은 stream을 리턴한다는 것이다.
이때는 map 메서드를 실행하면서 전달해준 function을 처리해도 출력이 되지 않는다.
이런 중계형 operator들은 terminal operator가 오기 전까지는 실행하지 않는다. 그냥 정의만 한 것이 된다.
stream 파이프라인(중계 operator를 0, 또는 여러 개 넣을 수 있다)의 끝에는 반드시 terminal, 종료형 operation이 와야 한다.
위 사진을 보면 stream()으로 collect(Collectors.toList())까지 한 반환 타입이 List인 것을 볼 수 있다. 이는 collect()가 종료형 operator인 것을 알 수 있다.
이렇게 원본 소스는 바뀌지 않으면서 대문자로 운동 종목들도 출력할 수 있다.
굳이 어렵게 stream을 쓰지 않고 향상된 for문을 사용하면 되지 않을까라고 생각할 수도 있다.
for(String sport : sports) {
if(sport.startsWith("b")) {
System.out.println(sport.toUpperCase());
}
}
지금은 이렇게 간단해보이지만, 조금만 로직이 더 추가된다면 코드가 복잡해질 수 있다. 또한, 근본적으로 for문 같은 loop형 코드는 병렬적으로 처리하기가 어렵다.
sports.parallelStream()
stream은 for문과 같은 loop형과 달리, parallelStream()을 활용하여 병렬적으로 처리할 수 있다. 이는 jvm이 알아서 병렬적으로 처리를 해주는 것이다. parallelStream() 안에는 spliterator()가 내장되어 있기에, trySplit()으로 stream을 쪼개서 처리를 하게 된다. 그러면 뒤에 오는 operator들이 병렬적으로 처리된다.
이렇게 collect()를 통해서 모은 후 이를 출력하는 식으로 활용할 수 있다.
추가 실험
Thread의 이름을 출력하면서 스트림으로 모은 List를 출력한 결과, 중간에 ForkJoinPool을 써서 병렬적으로 처리가 되는 것을 볼 수 있다. 각각의 다른 스레드가 사용된 것을 알 수 있다.
parallelStream()이 아닌 stream()을 사용하면 동일한 스레드에서 실행된다.
스레드를 만들고, 이 스레드들에서 병렬적으로 처리하고 수집하는 동안의 비용, 스레드 간에 왔다갔다하는 context switching 비용 등이 오히려 한 스레드에서 처리하는 것보다 더 오래걸릴 수 있다.
그럼에도 병렬 처리가 유용하게 쓰이는 때는 데이터가 정말 방대하게 큰 경우에는 유용하다.
케이스마다 성능 측정해서 parallelStream()으로 바꿨을 때 효과가 있는지 직접 확인하는 게 좋을 것이다.