스트림 vs 컬렉션

반응형
728x90
반응형

스트림과 컬렉션

자바의 기존 컬렉션과 새롭게 추가된 스트림 모두 연속된 요소 형식의 값을 저장하는 자료구조의 인터페이스를 제공한다. 연속된이란, 순서와 상관없이 아무 값에나 접속하는 것이 아닌 순차적으로 접근한다는 것을 의미한다. 스트림과 컬렉션의 차이는 데이터를 언제 계산하느냐이다.

 

1) 컬렉션

컬렉션은 현재 자료구조가 포함하는 모든 값을 메모리에 저장하는 자료구조다. 따라서 컬렉션의 모든 요소는 컬렉션에 추가하기 전에 계산되어야한다.

 

2) 스트림

스트림은 요청할 때만 요소를 계산하는 고정된 자료구조이다. 스트림에 요소를 추가하거나 스트림에서 요소를 제거할 수 없다.
사용자가 요청한 값만 스트림에서 추출한다.

스트림은 생산자(producer)-소비자(consumer) 관계를 형성한다.
사용자가 데이터를 요청할 때에만 값을 계산한다.

 

또다른 예시로 브라우저 인터넷 검색을 보자. 검색어를 입력하였을때, 그림을 포함한 모든 검색 결과를 내려받을때까지 기다리지 않아도 가장 비슷한 결과 요소를 포함하는 스트림을 얻을 수 있다. 반면에 컬렉션은 모든 값을 계산할때까지 즉, 모든 검색 결과를 내려받을 때까지 기다린다.

 

 

 

스트림의 단 한번의 탐색

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

 

List<String> title = Arrays.asList("kim", "seo", "hae");
Stream<String> s = title.stream();
s.forEach(System.out::println);
s.forEach(System.out::println); // java.lang.IllegalStateException : 스트림이 이미 소비되었거나 닫힘

 

위 코드에서 보듯이, 스트림은 단 한번만 소비할 수 있다.
만약 한 번의 소비 이후에 다시한번 호출한다면 java.lang.IllegalStateException 에러가 발생한다.

 

 

 

외부반복과 내부반복

외부반복 : 컬렉션 인터페이스를 사용하려면 사용자가 직접 요소를 반복해야한다.

List<String> names = new ArrayList<>();
for (Dish dish : menu) {
  names.add(dish.getName());
}

 

내부반복 : 스트림 라이브러리는 반복을 알아서 처리하고 결과 스트림 값을 저장해준다.

List<String> names = menu.stream()
                        .map(Dish::getName)
                        .collect(toList()); // 파이프라인을 실행한다.

 

위 외부반복, 내부반복의 예제 코드를 보면 코드의 차이밖에 느껴지지 않는다. 어떤 점이 다르며 내부반복이 어떠한 이득을 주는지 분석해보자.

 

1) 외부반복은 명시적으로 컬렉션 항목을 하나씩 가져와서 처리한다.
2) 내부반복은 작업을 투명하게 병렬로 처리하거나 더 최적화된 다양한 순서로 처리할 수 있다.
3) 내부반복은 데이터 표현과 하드웨어를 활용한 병렬성 구현을 자동으로 선택한다.
4) 외부 반복은 for-each 등을 사용할때 병렬성을 스스로 관리해야한다.

 

결과적으로 자바 8에서는 스트림을 통해 반복자 없이 내부반복이 가능하게 되었다. 스트림은 내부 반복을 사용하므로 반복 과정을 우리가 신경쓰지 않아도 된다. 우리는 이와 같은 이점을 누리기 위해 filter, map과 같은 반복을 숨겨주는 연산 리스트가 미리 정의되어 있어야한다.

 

반응형

'Coding > Java' 카테고리의 다른 글

싱글턴 패턴  (0) 2020.11.06
스트림 연산  (0) 2020.11.06
스트림 구현  (0) 2020.11.06
스트림의 기본개념  (0) 2020.11.06
람다의 메서드 참조  (0) 2020.11.06

Designed by JB FACTORY