item 45) 스트림은 주의해서 사용하라
스트림 파이프라인
스트림(stream)
데이터 원소의 유한 혹은 무한 시퀀스를 의미
컬렉션, 배열, 파일, 정규표현식 패턴 매치, 난수 생성기, 혹은 다른 스트림 등에서 데이터 원소들을 가져온다.
스트림 파이프라인은 스트림 원소들로 수행할 수 있는 연산 단계를 표현한다.
소스 스트림 -> (하나 이상의 중간연산) -> 종단연산 으로 구성된다.
종단 연산: 마지막 중간 연산이 반환한 스트림에 최후의 연산을 수행한다. 대표적으론 원소를 정렬해 컬렉션에 담거나, 특정 원소 하나를 선택하거나, 모든 원소를 출력하는 등의 연산을 한다. 스트림 파이프라인에 필수적이다.
지연 평가(lazy evaluation): 계속해서 합쳐진 중간연산들을 한번에 최종 연산으로 처리하며, 평가는 종단 연산이 호출될 때 이루어진다.
메서드 연쇄를 제공하여 파이프라인 하나를 구성하는 모든 호출을 연결해 단 하나의 표현식으로 완성할 수 있는 fluent API이다.
기본적으로 순차적 수행이며, parallel 메서드를 통해 병렬 실행 가능하지만 효과를 보긴 어렵다 (item48)
스트림 사용하기
스트림 변수의 이름을 지어 스트림 안의 원소가 어떤 것인지 명확히 하면 좋다.
기본 타입인 char용 스트림을 지원하지 않으므로 char 값들을 처리할 때는 스트림을 사용하지 말고 메서드를 정의해 사용하자.
chars() 메서드는 int 원소들을 반환한다.
코드 가독성과 유지보수 측면에서 손해볼 수 있으므로 스트림과 반복문을 적절히 조합하는 것이 최선이다.
기존 코드는 스트림을 사용하도록 리팩토링 하되, 새 코드가 나아보일 때에만 반영한다.
스트림 파이프라인은 되풀이되는 계산을 함수 객체(람다/메서드참조)로 표현한다.
코드 블록 vs 람다
코드 블록은 범위 안의 지역변수를 읽고 수정할 수 있다. 람다에서는 final이거나 사실상 final인 변수만 읽을 수 있다.
코드 블록은 return 문을 사용해 메서드에서 빠져나가거나, break, continue문 사용하거나, 메서드 선언에 명시된 검사 예외를 던질 수 있다. 람다에서는 불가능하다.
스트림의 특징
스트림은 원소의 시퀀스를 일관되게 변환하거나, 필터링하거나, 하나의 연산으로 결합하거나, 컬렉션에 모으거나, 특정 조건 검사할 때 적합하다.
다음 단계로 넘어갈 때 원래 값을 버리고 새로운 값만 가지므로, 파이프라인의 여러 단계들에서의 값들에 대한 동시 접근이 어렵다.
앞 단계의 값이 필요할 때 거꾸로 매핑해 값을 구해내는 방식이 가능하다면 이 방식을 사용하도록 한다.
스트림을 반환하는 메서드 이름은 원소의 정체를 알려주는 복수 명사로 사용하는 게 좋다.
아래는 suit 하나 당 Rank의 value마다 새로운 Card 객체를 만들어내어 collect하는 예제이다.
flatMap: 스트림의 원소 각각을 하나의 스트림으로 매핑한 후 다시 하나의 스트림으로 합치는 평탄화 과정
결국, 반복 방식과 스트림을 조합했을 때 가장 효과적이다.
두 방식 중 어떤게 나은지 확인하기 위해서는 둘 다 사용해보고 선택하는게 좋다.
Last updated