아이템 45. 스트림은 주의해서 사용하라

문법식·2022년 10월 4일
0

Effective Java 3/E

목록 보기
45/52

스트림 API는 다량의 데이터 처리 작업을 돕기 위해 자바 8에 추가됐다. 스트림 API의 핵심 개념은 두 가지다. 첫 번째인 스트림은 데이터 원소의 유한 혹은 무한 시퀀스를 뜻한다. 두 번째인 스트림 파이프라인은 이 원소들로 수행하는 연산 단계를 표현하는 개념이다. 스트림의 대표적인 원소들은 컬렉션, 배열, 파일, 정규표현식 패턴 매처, 난수 생성기, 혹은 다른 스트림이 있다. 스트림 안의 데이터 원소들은 객체 참조나 기본 타입 값이다. 기본 타입 값으로는 int, long, double을 지원한다.

스트림 파이프라인은 소스 스트림에서 시작해 종단 연산으로 끝나며, 그 사이에 중간 연산이 있을 수 있다. 중간 연산들은 모두 한 스트림을 다른 스트림으로 변환하는데, 변환된 스트림의 원소 타입은 변환 전 스트림의 원소 타입과 같을 수도 있고 다를 수도 있다. 종단 연산은 마지막 중간 연산이 내놓은 스트림에 최종 연산을 한다. 원소를 정렬해 컬렉션에 담거나, 특정 원소 하나를 선택하거나, 모든 원소를 출력하는 식이다.

스트림 파이프라인은 지연 평가된다. 평가는 종단연산이 호출될 때 이뤄지며, 종단 연산에 쓰이지 않는 데이터 원소는 연산에 쓰이지 않는다. 지연 평가는 무한 스트림을 다룰 수 있게 해준다. 종단 연산이 없는 스트림 파이프라인은 아무 일도 하지 않는 명령어인 no-op과 같으니, 종단 연산을 빼먹으면 안 된다.

스트림 API는 메서드 연쇄를 지원하는 플루언트 API이다.

기본적으로 스트림 파이프라인은 순차적으로 수행된다. 파이프라인을 병렬로 실행하려면 파이프라인을 구성하는 스트림 중 하나에서 parallel 메서드를 호출해주기만 하면 되나, 효과를 볼 수 있는 상황이 많지 않다.

스트림을 제대로 사용하면 프로그램이 짧고 간단해지지만, 스트림을 잘못 사용하거나 과용하면 프로그램을 읽거나 유지보수하기 어려워진다. 또한 자바가 기본 타입인 char용 스트림을 지원하지 않기 때문에 char 값들을 처리하는 스트림은 명확성이 떨어지고 잘못 구현할 가능성이 커지고, 심지어 느려진다. char 값들을 처리할 때는 스트림으 삼가하는 편이 낫다.

기존 코드에서 스트림을 사용하도록 리팩토링 해보고, 더 나아 보일 때만 반영한다.

스트림이 처리하기에 적합한 작업의 유형이다.

  • 원소들의 시퀀스를 일관되게 변환한다.
  • 원소들의 시퀀스를 필터링한다.
  • 원소들의 시퀀스를 하나의 연산을 사용해 결합한다.(더하기, 연결하기, 최솟값 구하기 등)
  • 원소들의 시퀀스를 컬렉션에 모은다.
  • 원소들의 시퀀스에서 특정 조건을 만족하는 원소를 찾는다.

한편 스트림으로 처리하기 어려운 일도 있다. 대표적인 예로, 한 데이터가 파이프라인의 여러 단계를 통과할 때 이 데이터의 각 단계에서의 값들에 동시에 접근하기는 어려운 경우다. 스트림 파이프라인은 일단 한 값을 다른 값에 매핑하고 나면 원래의 값을 잃는 구조이기 때문이다.

스트림을 반환하는 메서드 이름은 원소의 정체를 알려주는 복수 명사로 쓰면 좋다.

결론은 스트림을 사용하면 좋은 경우가 있고 반복을 사용하면 좋은 경우가 있다. 어느 쪽을 선택하는 규칙은 없지만 위에서 언급한대로 참고할 만한 지침은 있다. 스트림과 반복 중 어느 쪽이 나은지 확신하기 어렵다면 둘 다 해보고 더 나은 쪽을 택하라.

profile
백엔드

0개의 댓글