스트림
스트림(Stream)은 Java8부터 추가된 컬렉션(배열 포함)의 요소를 하나씩 참조해 람다식으로 처리할 수 있도록 하는 반복자이다.
데이터 처리 연산을 지원하도록 소스에서 추출된 연속된 요소
List<String> list = Arrays.asList("A", "B", "C", "D");
// 스트림 사용❌
Iterator<String> iter = list.iterator();
while(iter.hasNext()){
String name = iter.next();
System.out.println(name);
}
// 스트림 사용⭕
Stream<String> stream = list.stream();
list.stream().forEach(name -> System.out.println(name));
특징
선언형
- 선언형으로 코드를 구현할 수 있어 변하는 요구사항에 쉽게 대응이 가능
- 대부분의 요소 처리 메소드는 함수적 인터페이스 매개 타입이다
- 간결하고 가독성이 향상
조립 가능
- 빌딩 블록 연산을 연결해 데이터 처리 파이프라인을 만들 수 있어 가독성과 명확성이 유지
- 중간 처리(map, fliter, sort)와 최종 처리(forEach, count, sum) 등의 처리가 가능
병렬화
- 내부 반복자를 사용해 병렬처리가 쉬워진다
- 개발자는 요소당 처리해야할 코드만 작성하고 요소의 반복은 컬렉션에게 위임한다
- 병렬로 실행이 가능해 성능이 향상
- 요소들의 반복 순서를 변경하거나 CPU를 최대한 활용하기 위해 병렬 작업을 하도록 돕기 때문에 한 개씩 처리하는 외부 반복자보다 효율적이다
- 스레드와 락을 걱정하지 않아도 된다
💡 병렬(parallel) 처리
한가지의 작업을 서브 작업으로 나누고 서브 작업들을 분리된 스레드에서 병렬적으로 처리하는 것
런타임시 하나의 작업을 서브 작업으로 자동으로 나누고, 서브 작업의 결과를 결합해 최종 결과물을 생성
- 순차 처리 스트림 -> 하나의 스레드가 요소들을 순차적으로 읽고 합을 구함
- 병렬 처리 스트림 -> 여러 개의 스레드가 요소들을 부분적으로 합하고 최종 결합해 전체의 합을 생성
일회성
- 스트림은 한 번만 탐색이 가능하고 탐색된 스트림은 소비
- 다시 탐색하려면 새로운 스트림을 생성해야 함
List<String> list = Arrays.asList("A", "B", "C", "D");
Stream<String> stream = list.stream();
stream.forEach(System.out::println);
stream.forEach(System.out::println); // java.lang.IllegalStateException 발생
외부 반복 & 내부 반복
사용자가 직접 요소를 반복하는 것을 외부 반복(external iteration), 스트림은 반복을 알아서 처리하고 결과 스트림값을 어딘가에 저장해주는 내부 반복(internal iteration)을 사용한다.
// 외부 반복
List<String> list = new ArrayList<>();
Iterator<String> iter = member.iterator();
while(iter.hasNext()){
Member member = iter.next();
if(member.getAge() >= 20){
list.add(member.getName());
}
}
// 내부 반복
List<String> list = member.stream()
.filter(m -> m.getAge() >= 20)
.collect(toList());
내부 반복을 사용하면 작업을 투명하게 병렬적으로 처리하거나 최적화된 다양한 순서로 처리가 가능하다. 외부 반복에서는 병렬성을 스스로 관리(synchronized 사용)해야 한다.
스트림 연산
중간 연산
중간 처리 메소드는 중간 처리된 스트림을 리턴하고, 이 스트림에서 다시 중간 처리된 메소드를 호출할 수 있어 파이프라인을 형성한다.
특징은 단말 연산을 스트림 파이프라인에 실행하기 전까지는 아무 연산도 수행하지 않는다 => 게으르다(lazy)
중간 연산을 합친 다음 합쳐진 중간 연산(loop fusion)을 최종 연산으로 한번에 처리한다.
ex) filter, map, limit, sorted, distinct, peek ...
최종 연산
스트림 파이프라인에서 기본형이나 Optional 등 스트림 이외의 결과를 도출한다.
ex) forEach, count, collect, match ...
📚 Reference
신용권, 『이것이 자바다』, 한빛미디어(2015)
라울-게이브리얼 우르마, 『모던 자바 인 액션』, 우정은, 한빛미디어(2018)
'Programming > Java' 카테고리의 다른 글
[Java] String.replaceAll() 활용하기 (0) | 2021.05.19 |
---|---|
[Java] 스트림(Stream) 활용 (0) | 2021.05.13 |
[Java] 람다(lambda) (0) | 2021.05.06 |
[Java] Boxing, Unboxing (0) | 2021.05.05 |
[Java] Arrays.sort(), Collections.Sort() 속도 비교 (0) | 2021.03.04 |