프로그래밍/JAVA Spring

[JAVA 자바/이펙티브 자바] 아이템 46. 스트림에서는 부작용 없는 함수를 사용하라

hectick 2023. 3. 19. 20:23

 

스트림에서는 부작용 없는 함수를 사용하라

 

 

 

🐣 부작용이 없다?

 

- 오직 입력만이 결과에 영향을 줘야 한다. 

- 다른 가변 상태를 참조하지 않고, 함수 스스로도 다른 상태를 변경하지 않는다.

 

이것을 `순수 함수`라고 부른다.

 

 

다음 예시에선, 스트림의 forEach에서 외부의 results를 참조하고, results의 상태를 변경하게 되는 부작용이 발생한다.

    ArrayList<String> results = new ArrayList<>();
         stream.filter(s -> pattern.matcher(s).matches())
               .forEach(s -> results.add(s));

아래처럼 고치는게 좋다.

     List<String>results =
         stream.filter(s -> pattern.matcher(s).matches())
               .collect(Collectors.toList());

 


'모던 자바 인 액션' 책에서는 부작용을 포함하는 함수를 사용하면 부정확하거나 예상치 못한 결과가 나올 수 있다는 문제가 있다한다. 하지만 내가 지금까지 했던 프로그래밍에선 이런 상황은 아직 없었다. 바로 아래에서 예시로 한줄 쓴게 처음이다. '병렬로 실행하는' 복잡한 프로그램을 만들어야 나오는 문제인 것 같아서 지금의 나에겐 와닿지 않는다. 그래서 일단 이 정도로만 이해하고 넘어가겠다.

스트림에서 공유되는 가변 데이터를 사용한다면, 여러 곳에서 그 데이터를 동시에 사용하거나 수정하는 상황일 때, 예상치 못한 결과가 나올 수 있다. 그래서 스트림에서는 부작용 없는 함수를 사용해야 언제나 올바른 결과를 도출할 수 있다.

 

 

 

🐣 더불어, forEach는 계산 결과를 보고할 때만 사용하고, 계산할 때는 쓰지 않는 것이 좋다

 

forEach는 스트림에서 최종연산에 해당한다. forEach에 스트림이 수행한 연산 결과를 보여주는 일 이상의 로직을 넣는 것은 최종연산답지 못하다. 만약 forEach 내부에 로직을 넣었다면, 이것을 중간연산으로 뺄 수 있는지 확인해봐야 할 것이다. forEach가 아닌 다른 최종연산을 쓸 수 있는지 찾아보는 것도 좋다.

 

 

이펙티브 자바에 따르면 forEach는 최종연산 중 가장 '덜' 스트림답다고 한다. 왜 가장 '덜' 스트림 답다고 할까?

 

forEach는 대놓고 반복적이다. 스트림은 외부반복이 아닌, 내부반복을 지원한다. 하지만 forEach는 외부에서 반복하는 내용을 볼 수 있다. 내부반복의 이점은 작업을 투명하게 병렬로 처리할 수 있다는 것인데, 책 저자에 따르면 forEach는 대놓고 반복적이라 병렬화할 수 없다. 즉, forEach는 외부에서 명시적으로 반복을 볼 수있을 뿐더러, 스트림의 이점인 '병렬성'을 살리지 못하기 때문에 덜 스트림답다고 하는 것 같다.

 

'병렬화 할 수 없다' 라는 말이 무슨 의미인지 이해해보기 위해 간단한 코드를 조금 써봤다. 윗줄 코드는 병렬처리로 forEach를 실행하는 것, 아래 코드는 병렬처리 안하는 것이다.

	Stream.of("이리내", "깃짱", "오잉", "푸우", "네오", "콩하나").sorted().parallel().forEach(System.out::println);

	Stream.of("이리내", "깃짱", "오잉", "푸우", "네오", "콩하나").sorted().forEach(System.out::println);

출력 결과는 윗줄 코드는 실행할 때마다 매번 이름 순서가 다르게 출력되는 반면, 아래 코드는 항상 가나다 순서대로 출력된다. 만약 forEach로 병렬처리를 할 수 있다 하더라도, 병렬처리로 인해 내가 원하는 결과와는 다르게, 그리고 실행할 때마다 매번 출력 순서가 바뀌기 때문에 사실상 forEach로 병렬처리는 못하는거라 생각해야 할 것 같다.

 

 

 


이펙티브 자바를 읽으면서 개인적인 이해를 돕기위해 작성한 내용입니다.

잘못된 내용이 있다면 댓글로 알려주세요