Dev/Java
[모던자바인액션] 컬렉션과 스트림의 차이점(Stream vs Collection)
ssyoni
2022. 1. 28. 16:01
반응형
스트림과 컬렉션
자바의 기존 컬렉션과 새로운 스트림은 순차적으로 값에 접근한다.
DVD와 인터넷 스트리밍을 예로 비교해보자.
DVD는 이미 영화가 저장되어서 판매된다. 이는 컬렉션에 비유할 수 있다.
반면 인터넷 스트리밍은 사용자가 시청하는 부분의 몇 프레임을 미리 내려받는다.
때문에 대부분의 값을 처리하지 않은 상태에서 미리 내려받은 프레임부터 재생이 가능하다. 이를 스트림으로 비유할 수 있다.
컬렉션 = DVD
- 자료구조가 포함하는 모든 값을 메모리에 저장한다.
- 컬렉션의 모든 요소는 컬렉션에 추가하기 전에 계산되어야 한다.
- 생산자 중심 → 팔기도 전에 창고를 가득 채움.
- 만약 소수를 저장하는 컬렉션을 만들 시에, 끝도 없이 모든 소수를 포함하려 할 것이므로 무한루프를 돌게 된다.
- 영화의 모든 프레임들이 미리 저장되어있는 DVD
- 적극적 생성 → 모든 값을 계산할 때까지 기다린다.
스트림 = 인터넷 스트리밍
- 요청할 때만 요소를 계산한다. 고정된 자료구조. → 스트림에 요소를 추가하거나 제거할 수 없다.
- 사용자가 요청하는 값만 스트림에서 추출한다.
- 생성자와 소비자의 관계를 형성한다.
- 게으른 생성 → 필요할 때만 값을 계산한다.
스트림은 딱 한 번만 탐색이 가능하다.
탐색된 스트림의 요소는 소비된다.
때문에 한 번 탐색한 요소를 다시 탐색하려면 초기 데이터 소스에서 새로운 스트림을 생성해야 한다.
그러려면 컬렉션처럼 반복 사용할 수 있는 데이터 소스여야 한다.
데이터 소스가 I/O 라면 소스를 반복 사용할 수 없기 때문에 새로운 스트림을 생성할 수 없다.
List<String> title = Arrays.asList("Java8","In","Action");
Stream<String> s = title.stream();
s.forEach(System.out::println);
s.forEach(System.out::println); // Java.lang.IllegalStateException
스트림이 이미 소비되었거나 닫혔기 때문에 두 번째 출력 부분에서 Java.lang.IllegalStateException 에러가 발생한다.
외부 반복과 내부 반복
컬렉션과 스트림은 데이터 반복 처리 방법에서 차이가 있다.
컬렉션은 외부 반복을 사용한다. 외부 반복이란 사용자가 for-each 등을 사용해서 직접 요소를 반복하는 것을 말한다.
스트림은 내부 반복을 사용한다.
외부 반복
- 명시적으로 컬렉션 항목을 하나씩 가져와서 처리함
- 병렬성을 스스로 관리해야 한다.
내부 반복
- 작업을 투명하게 병렬로 처리할 수 있다.
- 더 최적화된 다양한 순서로 처리할 수 있다.
- filter 나 map 같이 반복을 숨겨주는 연산 리스트가 미리 정의되어 있어야 한다.
- 반복을 숨겨주는 연산은 대부분 람다 표현식으로 인수를 받는다. 동작 파라미터화를 사용할 수 있다.
스트림 동작 리팩터링 해보기 예제
List<String> highCaloriesDishes = new ArrayList<>();
Iterator<String> iterator = menu.iterator();
while(iterator.hasNext()){
Dish dish = iterator.next();
if(dish.getCalories() > 300){
highCaloricDishes.add(d.getName());
}
}
List<String> highCaloriesDishes = menu.stream()
.filter(dish -> dish.getCalories() > 300)
.map(Dish::getName)
.collect(toList());
반응형