상세 컨텐츠

본문 제목

[모던 자바 인 액션] 컬렉션 vs 스트림 (Collection vs Stream)

Java/Modern Java in Action

by 개발하는 정복자 2022. 6. 26. 21:22

본문

 

모던 자바 인 액션 - YES24

자바 1.0이 나온 이후 18년을 통틀어 가장 큰 변화가 자바 8 이후 이어지고 있다. 자바 8 이후 모던 자바를 이용하면 기존의 자바 코드 모두 그대로 쓸 수 있으며, 새로운 기능과 문법, 디자인 패턴

www.yes24.com


스트림과 컬렉션

스트림과 컬렉션 모두 연속된 요소 형식의 값을 저장하는 자료구조의 인터페이스를 제공한다.

'연속된' 이란 순서와 상관없이 아무 값이나 접속하는 것이 아니라 순차적으로 값에 접근한다는 것을 의미

 

👉🏾 차이점

스트림과 컬렉션의 가장 큰 차이는 '언제 계산하느냐 '(계산 시점)로 나눌 수 있다.

 

  자료구조 특징 추가 삭제 가능 여부 생성(경제학 예시)
컬렉션 모든 요소는 컬렉션에 추가
되기 전
에 계산
 ⭕️  게으른 생성(요청 중심 제조)
스트림 요청할 때만 요소를 계산 적극적 생성(즉석 제조)

 

👉🏾 계산 시점 예시

 

컬렉션 : DVD로 영화 시청 (적극적 생성)

DVD에 저장된 모든 값을 처리 후 재생할 수 있다.

 

스트림 : 인터넷 스트리밍으로 영화 시청 (게으른 생성)

사용자가 시청하는 부분을 몇 프레임을 미리 내려받는다. 스트림의 대부분의 값을 처리하지 않은 상태에서 미리 내려받은 프레임부터 재생할 수 있다. 비디오 재생기는 모든 프레임을 내려 받을 만큼 충분한 메모리가 없을 수도 있고 있다고 하더라도 모든 프레임을 내려받고 재생을 시작하면 내려받기위한 로딩시간이 많이 필요할 것이다.

출처 Mordern Java in Action

출처: Morder Java in Action

👉🏾 소수 예제

컬렉션은 끝이 없는 모든 소수(2, 3, 5, 7, 11, ...)를 포함하려 하며 무한 루프를 돌면서 새로운 소수를 계산하고 추하하기를 반복한다. 고로 영원히 결과를 볼 수 없다. 그러나 스트림은 사용자가 요청하는 즉시 값을 계산하여 이 문제를 해결할 수 있다.

 


 

 딱 한 번만 탐색할 수 있다

반복자와 마찬가지로 스트림도 한 번만 탐색할 수 있다. 탐색된 스트림의 요소는 소비된다.탐색한 요소를 다시 탐색하려면 초기의 데이터 소스에서 새로운 스트림을 만들어야 한다. (컬렉션처럼 반복 가능한 데이터 소스여야 한다.)

 

예시 👇🏾

	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: 스트림이 이미 소비되었거나 닫힘.

 


 

외부 반복과 내부 반복

 

  반복 병렬성
컬렉션 외부 반복 스스로 관리
스트림 내부 반복 자동으로 선택됨

 

 

👉🏾 컬렉션의 외부 반복

List<Dish> menu = Dish.getDishes();
List<String> names = new ArrayList<>();
for( Dish dish : menu) {    // 메뉴 리스트를 명시적으로 순차 반복한다.
    names.add(dish.getName());  // 이름을 추출해서 리스트에 추가한다.
}

 

👉🏾 스트림의 내부 반복

List<Dish> menu = Dish.getDishes();
List<String> names = menu.stream()
	.map(Dish::getName)		// map 메서드를 getName 메서드로 파라미터화해서 요리명을 추출한다.
	.collect(Collectors.toList());	// 파이프라인을 실행한다. 반복자는 필요없다.

 

👉🏾 내부 반복과 외부 반복 차이 예시

A: "B, 장난감 좀 정리하자. 방바닥에 장난감 있지?"

B: "응, 공 있어"

A: "오케이, 그럼 공을 상자에 담아. 또 어떤 장난감이 있지?"

B: "인형 있어"

A: "그럼 인형 담아. 또 어떤 장난감 있지?"

B: "책 있어"

A: "그럼 책 담자. 또 어떤게 있지?"

B: "아무것도 없어"

A: "오게이 잘했다!"

 

위 대화는 명시적으로 컬렉션 항목을 하나씩 가져와서 처리하는 컬렉션의 외부 반복이다. 우리의 목적은 그저 모든 장난감을 상자에 전부 담는 것 인데 굳이 하나씩 처리해야 할까? 스트림의 내부 반복은 그저 "모든 장난감을 전부 상자에 담아"라고 말하면 끝이다. 또 한 손에는 인형을 다른 손에는 공을 동시에 들 수 있고, 먼저 모든 장난감을 상자 가까이 이동시킨 다음 장난감을 상자에 담는다.

 

                                                                                     출처: Mordern Java in Action

스트림은 내부 반복을 사용하므로 반복 과정을 우리가 신경쓰지 않아도 된다. 

 

👉🏾 반복속 병렬성

내부 반복은 데이터 표현과 하드웨어를 활용한 병렬성 구현을 자동으로 선택한다.

반면 외부 반복은 병렬성을 스스로 관리해야 한다. (병렬성을 스스로 관리하는 것은 매우매우 어렵다)

관련글 더보기

댓글 영역