본문으로 바로가기

Java Collections.forEach vs Collections.stream().forEach()

category Java 2021. 9. 28. 23:33

https://wnwngus.tistory.com/58

 

Java Enhanced for-loop vs Collecions.forEach()

https://wnwngus.tistory.com/57?category=891308 Java for-loop vs Enhanced for-loop 알고리즘을 제외하고 다른 내용에 대해 포스팅을 하고 싶다고 생각해왔다. 사실 알고리즘을 올리는 것도, 별도의 프로젝트를..

wnwngus.tistory.com

 

이전 글을 혹시 읽지 않으셨다면 읽고 와주세요!

 

이번 글은 forEach() 시리즈의 마지막 글입니다.

 

이번 글에서는 지난 번 글에서 다뤘던  Collections.forEach() 와 Collections.stream().forEach()의 차이점을 알아보고,  stream().forEach()와 parallelStream().forEach()의 차이점에 대해서 알아보는 것으로 forEach 시리즈의 마무리를 지어볼까 합니다.

 

이 차이점에 대해 이해하자면,  먼저 Stream 객체에 대해 이해할 필요가 있습니다.

 

Collections.stream() 은 Stream 객체를 생성하는 메서드이다. 그리고 그 Stream 객체의 특징은, 아래와 같이 요약할 수 있습니다.

 

  • 일회성이다.
  • 원본(Stream 객체의 부모)의 값을 변경하지 않는다.

Stream 객체를 생성할 때에 원본 값을 조회한 다음 그 데이터가 아니라 별도로 Stream을 생성하기 때문에, Stream 객체를 이용한 작업은 원본의 값에 영향을 끼치지 않습니다. 또한 한번 사용한 Stream은 재사용할 수 없기 때문에 사용에 주의를 요합니다.(Stream을 재사용하려고하면 illegalStateException이 발생한다.)

 

이정도의 설명을 들으면, 자연스럽게 이러한 추측을 할 수 있습니다.

 

Collections.forEach()는 내부적으로 iterator를 사용하여 loop를 돈다고 했는데, 그렇다면 Collections.stream().forEach()는 중간에 Stream 객체의 생성이 들어가 있기 때문에 소모값이 더 큰가?

 

 

실제로 제대로 공부하지 않고 stream().forEach()를 알고리즘 문제를 풀 때 사용한 적이 있었는데, 그때 올바른 로직이었음에도 효율성을 통과하지 못한 경험이 있습니다. (이러한 내용을 공부하게된 계기이기도 합니다.)

 

따라서 단순 반복이 목적이라면, stream().forEach()는 Stream 객체의 생성과 닫힘이라는 오버헤드가 존재하기 때문에, filter라던가 map 등의 Stream 가공이 필요한 반복이 아니라면 사용을 지양해야 합니다.

 

Stream 객체의 사용 이외에도, stream().forEach는 내부적으로 spliterator를 사용한다는 차이점이 있고, 그에 따라서 Collections.forEach()에는 synchronized가 붙어있어 멀티스레드 환경에서 락이 걸리고 stream().forEach는 그렇지 않다는 차이점도 있습니다. 이러한 iterator와 iterable에 대한 차이점은 추후 다른 글에서 자세히 공부하여 포스팅하도록 하겠습니다.

 

마지막으로 stream().forEach()와 parallelStream().forEach()는 Multi thread로 처리를 제공하는가 하지 않는가의 차이가 있습니다.

 

Collection.parallelStream()은 병렬로 동작하는 Stream 객체를 리턴하고, stream()의 경우에는 Single thread로 동작하는 Stream을 리턴합니다. 따라서 

 

stream().forEach() 를 이용해 List의 내용물을 출력할 경우,

List<String> list =
        Arrays.asList("1", "2", "3", "4", "5");

list.stream().forEach(System.out::print);

위와 같은 코드를 실행할 경우, 출력 값은

 

12345

 

로 List의 순서를 그대로 따르게 됩니다.

 

그러나 parallelStream().forEach()의 경우, Multi thread로 동작하기 때문에 순서를 보장하지 않는다. 따라서 출력 결과가 리스트의 순서대로 나오는 것을 보장하지 않습니다.

 

34125

(이처럼 섞여나올 수 있다는 이야기)

 

 

결론을 요약해보자면 이렇습니다.

 

Collections.forEach() / Collections.stream().forEach() / Collections.parallelStream().forEach() 

 

단순 반복을 위해서라면 Collections.forEach()

Stream API의 Stream 가공(filter, map 등)이 필요하다면 Collections.stream().forEach()

모종의 병렬처리가 필요하다면 Collections.parallelStream().forEach()

'Java' 카테고리의 다른 글

Java Enhanced for-loop vs Collecions.forEach()  (1) 2021.09.23
Java for-loop vs Enhanced for-loop  (2) 2021.09.22