스트림은 데이터 원소의 유한 혹은 무한 시퀀스를 뜻한다.
스트림 파이프라인은 이 원소들로 수행하는 연산 단계를 표현하는 개념이다.
스트림 파이프라인은 소스 스트림에서 시작해 종단 연산으로 끝나며, 그사이에 하나 이상의 중간 연산이 있을 수 있다.
각 중간 연산은 스트림을 어떠한 방식으로 변환한다.
스트림 파이프라인은 지연 평가된다.
평가는 종단 연산이 호출될 때 이뤄지며, 종단 연산에 쓰이지 않는 데이터 원소는 계산에 쓰이지 않느다.
이러한 지연 평가가 무한 스트림을 다룰 수 있게 해주는 열쇠다.
종단 연산이 없는 스트림 파이프라인은 아무 일도 하지 않는 명령인 no-op과 같으니, 종단 연산을 빼먹는 일은 절대 없어야 한다.
스트림 API는 메서드 연쇄를 지원하는 플루언트 API다.
즉, 파이프라인 하나를 구성하는 모든 호출을 연결하여 단 하나의 표현식으로 완성할 수 있다.
파이프라인 여러 개를 연결해 표현식 하나로 만들 수도 있다.
기본적으로 스트림 파이프라인은 순차적으로 수행된다.
파이프라인을 병렬로 실행하려면 파이프라인을 구성하는 스트림 중 하나에서 parallel 메서드를 호출해 주기만 하면 되나, 효과를 볼 수 있는 상황은 많지 않다.
그리고 기존 코드는 스트림을 사용하도록 리팩터링을 하되, 새 코드가 나아 보일 때만 이를 반영하자.
스트림 파이프라인은 되풀이되는 계산을 함수 객체로 표현한다.
반면 반복 코드에서는 코드 블록을 사용해서 표현한다.
그런데 함수 객체로는 할 수 없지만 코드 블록으로는 할 수 있는 일들이 있다.
계산 로직에서 이상의 일들을 수행해야 한다면 스트림과는 맞지 않는 것이다.
반대로 다음 일들에는 스트림이 아주 안성맞춤이다.
한편, 스트림으로 처리하기 어려운 일도 있다.
한 데이터가 파이프라인의 여러 단계를 통과할 때 이 데이터의 각 단계에서 값들에. 동시에 접근하기는 어려운 경우다.
스트림 파이프라인은 일단 한 값을 다른 값에 매핑하고 나면 원래의 값을 잃는 구조이기 때문이다.
원래 값고 새로운 값의 쌍을 저장하는 객체를 사용해 매핑하는 우회 방법도 있지만, 그리 만족스러운 해법은 아닐 것이다.
매핑 객체가 필요한 단계가 여러 곳이라면 특히 더 그렇다.
이런 방식은 코드 양도 많고 지저분하여 스트림을 쓰는 주목적에서 완전히 벗어난다.
가능한 경우라면, 앞 단계의 값이 필요할 때 매핑을 거꾸로 수행하는 방법이 나을 것이다.