스트림은 함수형 프로그래밍에 기초한 패러다임으로 데이터 컬렉션(모음집)의 반복 작업을 가독성 있게 처리해준다.
또한 자바에서는 Stream을 이용하면 멀티쓰레드를 따로 구현하지 않아도 병렬로 처리할 수 있다.
함수형 프로그램은 값을 입력받고 파라미터로 넘어온 값의 변경 없이 로직 처리후 값을 리턴하여 프로그램의 완결성을 높이다.
만약 Stream을 사용하지 않고 리스트에 필터, 정렬연산을 한다고 해보자
List<User> Users = new ArrayList<>();
//유저를 삽입하는 코드//
//필터링된 유저를 저장할 array
List<User> filteredUser = new ArrayList<>();
for( User iter : Users){
if(iter.weight>50){
filteredUser.add(iter);
}
}
Collections.sort(filteredUser,(a,b)->{
return a.age-b.age;
});
지금은 내용이 간단해 보이지만 여러 기능을 추가한다면 가독성도 떨어지고 중간에 잘못된 값들이 전달될 가능성이 높아보인다.
그렇다면 Stream을 이용해 작성하면 어떨까?
List<User> Users = new ArrayList<>();
//유저를 삽입하는 코드//
List<User> finalResults = Users.stream()
.filter(user->user.weight>50)
.sort(Comparator.comparing((User a, User b)->{return a.weight-b.weight;})
.collect(toList());
같은 로직이지만 보다더 간결하다. 거기에 지금은 나와있지 않지만 앞서 말한 것 처럼 병렬 연산도 가능하다.
다시 정리해서 말하자면
연속된 요소를 처리(로직수행) 을 지원해주는 요소이다.
위에서 본 스트림이 적용된 코드의 특징이 보이는가? 바로 스트림.로직().로직().로직() 으로 연결되어 있다는 것이다. 이렇게 파이프라인으로 연결되어 있는 스트림은 한 로직의 결과가 다음 로직으로 자연스럽게 전달한다. 이때 Stream은 Laziness와 Short-circuiting을 통해 성능을 최적화 한다.
Stream은 중간연산과 최종연산으로 이루어져 있다. 이때 최종연산에 도달할 때 까지 실행될 파이프라인만 준비하여 마지막에 연산을 한다. 이를통해 필요할 때만 로직을 한번에 수행하게 하며 한번에 수행하면서 로직을 점검하여 불필요한 로직을 제거하여 성능 향상 시킨다.
Short-circuiting은 파이프라인으로 이어진 스트림에서 이미 이전 로직의 결과가 다음 로직의 결과와 같다면 다음 로직을 실행하지 않고 다음으로 뛰어넘어가 성능을 최적화 하는 것을 의미한다.내부반복
컬렉션들 List,Set은 외부에서 명시적으로 반복하지만 스트림은 내부 반복을 지원한다.
Stream을 이루는 연산은 크게 2개로 나눠진다.
스트림 연산 중간에 오며 앞서 말한 것 처럼 최종연산이 오기전 까지 아무연산을 하지 않고 연산을 준비만 한다.
스트림을 종료 시키고 값을 반환한다.