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());
반응형