
스트림 vs 컬렉션
데이터를언제 계산하느냐가 컬렉션과 스트림의 가장 큰 차이입니다.
컬렉션은 현재 자료구조가 포함하는 모든 값을 메모리에 저장하는 자료구조 입니다.
즉, 컬렉션의 모든 요소는 컬렉션에 추가하기 전에 계산되어 있어야 합니다.
스트림은 이론적으로 요청할때만 요소를 계산하는 고정된 자료구조 입니다.
(스트림에 요소를추가하거나 스트림에서 요소를 제거할 수 없습니다.)
사용자가 요청하는 값만 스트림에서 추출한다는 것이 핵심입니다.
결과적으로 스트림은 생산자와 소비자 관계를 형성합니다.
또한 스트림은 게으르게 만들어지는컬렉션과 같습니다.
사용자가 데이터를 요청할때만 값을 계산하기 때문입니다.
반면 컬렉션은 적극적으로 생성됩니다.
(사용자가 요청하기 전에 값을 전부 계산합니다.)
딱 한번만 탐색할 수 있다
스트림과 컬렉션 모두 딱한번만 탐색할 수 있습니다.
즉, 탐색된 스트림의 요소는 다시 탐색할 수 없습니다.
다시 탐색하려면 새로운 스트림이 필요합니다.
예제를 통해 알아보겠습니다.
public class SearchOnlyOneTime {
public static void main(String[] args) {
List<String> title = Arrays.asList("Java8", "In", "Action");
final Stream<String> stream = title.stream();
stream.forEach(System.out::println);
stream.forEach(System.out::println);
}
}
한번 사용한 스트림을 다시 한번 사용했습니다.
결과
Java8
In
Action
Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
at java.base/java.util.stream.AbstractPipeline.sourceStageSpliterator(AbstractPipeline.java:279)
at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762)
at part2_함수형데이터처리.chapter4_스트림소개.search.SearchOnlyOneTime.main(SearchOnlyOneTime.java:12)
Process finished with exit code 1
그 결과로 stream has already been operated upon or closed 예외가 발생했습니다.
스트림이 한번 소비되었기 때문입니다.
외부 반복과 내부 반복
컬렉션 인터페이스는 loop를 통해 외부 반복을 사용합니다.
반면 스트림 라이브러리는 내부 반복을 사용합니다.
(반복을 알아서 처리하고 결과 스트림값을 어딘가에 저장)
역시 코드를 통해 바로 알아보겠습니다
외부 반복
public class CollectionLoop {
public static void main(String[] args) {
List<String> names = new ArrayList<>();
final List<Dish> menu = Dish.menu;
for (Dish dish : menu) {
names.add(dish.getName());
}
System.out.println(names);
}
}
for-each를 통해 컬렉션의 데이터를 하나씩 전부 탐색하며 dish의 이름을 넣었습니다.
이처럼 데이터를 하나씩 반복하는 것을 외부 반복이라고 합니다.
내부 반복
final List<String> allNames = menu.stream()
.map((dish -> dish.getName()))
.collect(Collectors.toList());
System.out.println(allNames);
스트림은 데이터를 밖으로 꺼내서 사용하지 않고 데이터를 Stream 안에서 가져오는 방식입니다.
이것을 내부 반복이라고 합니다.
내부 반복과 외부 반복 효율성
내부 반복과 외부반복의 이해를 돕기위해 엄마와 아들이 이야기하는 내용을 가져와 보았습니다.
엄마 : "아들, 장난감좀 정리해. 방바닥에 장난감 있지?"
아들 : "네, 공이 있어요"
엄마 : "좋아, 그럼 공을 상자에 담자. 또 어떤 장난감이 있어?"
아들 : "인형이 있어요"
엄마 : "좋아, 그럼 인형을 상자에 담자. 또 어떤 장난감이 있어?"
아들 : "책이 있어요"
엄마 : "좋아, 그럼 책을 상자에 담자. 또 어떤 장난감이 있어?"
아들 : "아무것도 없어요"
엄마 : "참 잘했어."
이 내용은 자바 컬렉션에서 데이터를 탐색하는 방법과 같습니다.
완벽하게 일치하지는 않지만 위 대화를 코드로 해석해 보았습니다.
for-each : 엄마의 반복되는 질문
dish.getName : 아들의 대답
names.add : 그럼 "떙땡"을 상자에 담자
잘 보면 for-each를 통해 Collection의 값을 외부로 꺼내서 탐색하는 것을 확인 할 수 있습니다.
이것을 스트림으로 처리한다면 아래와 같이 처리할 수 있습니다.
엄마 : "아들 바닥에 있는모든 장난감을 상자에 담자."
스트림은 병렬적으로 데이터를 처리할 수 있는 장점도 있습니다.
즉, 아들의 손이 여러개가 생겨 장난감을 한번에 여러개씩 담을 수 있는 현실 세계에서는 비상식적이지만
효율적인 방법이 가능하다는 것입니다!
컬렉션도 병렬처리가 가능하지만, 스스로 관리해야 하기에 비용이 많이 들어가는 작업입니다.

정리
외부 반복
- 명시적으로 컬렉션 항목을 하나씩 가져와서 처리
- 병렬성을 스스로 관리해야 한다.
내부 반복
- 작업을 투명하게 병렬로 처리할 수 있다.
- 더 최적화된 다양한 순서로 처리할 수 있다.
- filter나 map 같이 반복을 숨겨주는 연산 리스트가 미리 정의되어 있어야 한다.
- 반복을 숨겨주는 연산은 대부분 람다 표현식으로 인수를 받는다. 즉, 동작 파라미터화를 할 수 있다.
'Books > Modern Java In Action' 카테고리의 다른 글
[모던 자바 인 액션] Chapter7. 병렬 스트림 (0) | 2023.08.03 |
---|---|
[모던 자바 인 액션] Chapter5. 함수형 데이터 처리 (0) | 2023.07.31 |
[모던 자바 인 액션] Chapter4. 스트림 소개 (0) | 2023.07.26 |
[모던 자바 인 액션] Chapter3. 람다 표현식 (0) | 2023.07.25 |
[모던 자바 인 액션] Chapter3. 동작파라미터화 코드 전달하기 (0) | 2023.07.22 |

스트림 vs 컬렉션
데이터를언제 계산하느냐가 컬렉션과 스트림의 가장 큰 차이입니다.
컬렉션은 현재 자료구조가 포함하는 모든 값을 메모리에 저장하는 자료구조 입니다.
즉, 컬렉션의 모든 요소는 컬렉션에 추가하기 전에 계산되어 있어야 합니다.
스트림은 이론적으로 요청할때만 요소를 계산하는 고정된 자료구조 입니다.
(스트림에 요소를추가하거나 스트림에서 요소를 제거할 수 없습니다.)
사용자가 요청하는 값만 스트림에서 추출한다는 것이 핵심입니다.
결과적으로 스트림은 생산자와 소비자 관계를 형성합니다.
또한 스트림은 게으르게 만들어지는컬렉션과 같습니다.
사용자가 데이터를 요청할때만 값을 계산하기 때문입니다.
반면 컬렉션은 적극적으로 생성됩니다.
(사용자가 요청하기 전에 값을 전부 계산합니다.)
딱 한번만 탐색할 수 있다
스트림과 컬렉션 모두 딱한번만 탐색할 수 있습니다.
즉, 탐색된 스트림의 요소는 다시 탐색할 수 없습니다.
다시 탐색하려면 새로운 스트림이 필요합니다.
예제를 통해 알아보겠습니다.
public class SearchOnlyOneTime {
public static void main(String[] args) {
List<String> title = Arrays.asList("Java8", "In", "Action");
final Stream<String> stream = title.stream();
stream.forEach(System.out::println);
stream.forEach(System.out::println);
}
}
한번 사용한 스트림을 다시 한번 사용했습니다.
결과
Java8
In
Action
Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
at java.base/java.util.stream.AbstractPipeline.sourceStageSpliterator(AbstractPipeline.java:279)
at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762)
at part2_함수형데이터처리.chapter4_스트림소개.search.SearchOnlyOneTime.main(SearchOnlyOneTime.java:12)
Process finished with exit code 1
그 결과로 stream has already been operated upon or closed 예외가 발생했습니다.
스트림이 한번 소비되었기 때문입니다.
외부 반복과 내부 반복
컬렉션 인터페이스는 loop를 통해 외부 반복을 사용합니다.
반면 스트림 라이브러리는 내부 반복을 사용합니다.
(반복을 알아서 처리하고 결과 스트림값을 어딘가에 저장)
역시 코드를 통해 바로 알아보겠습니다
외부 반복
public class CollectionLoop {
public static void main(String[] args) {
List<String> names = new ArrayList<>();
final List<Dish> menu = Dish.menu;
for (Dish dish : menu) {
names.add(dish.getName());
}
System.out.println(names);
}
}
for-each를 통해 컬렉션의 데이터를 하나씩 전부 탐색하며 dish의 이름을 넣었습니다.
이처럼 데이터를 하나씩 반복하는 것을 외부 반복이라고 합니다.
내부 반복
final List<String> allNames = menu.stream()
.map((dish -> dish.getName()))
.collect(Collectors.toList());
System.out.println(allNames);
스트림은 데이터를 밖으로 꺼내서 사용하지 않고 데이터를 Stream 안에서 가져오는 방식입니다.
이것을 내부 반복이라고 합니다.
내부 반복과 외부 반복 효율성
내부 반복과 외부반복의 이해를 돕기위해 엄마와 아들이 이야기하는 내용을 가져와 보았습니다.
엄마 : "아들, 장난감좀 정리해. 방바닥에 장난감 있지?"
아들 : "네, 공이 있어요"
엄마 : "좋아, 그럼 공을 상자에 담자. 또 어떤 장난감이 있어?"
아들 : "인형이 있어요"
엄마 : "좋아, 그럼 인형을 상자에 담자. 또 어떤 장난감이 있어?"
아들 : "책이 있어요"
엄마 : "좋아, 그럼 책을 상자에 담자. 또 어떤 장난감이 있어?"
아들 : "아무것도 없어요"
엄마 : "참 잘했어."
이 내용은 자바 컬렉션에서 데이터를 탐색하는 방법과 같습니다.
완벽하게 일치하지는 않지만 위 대화를 코드로 해석해 보았습니다.
for-each : 엄마의 반복되는 질문
dish.getName : 아들의 대답
names.add : 그럼 "떙땡"을 상자에 담자
잘 보면 for-each를 통해 Collection의 값을 외부로 꺼내서 탐색하는 것을 확인 할 수 있습니다.
이것을 스트림으로 처리한다면 아래와 같이 처리할 수 있습니다.
엄마 : "아들 바닥에 있는모든 장난감을 상자에 담자."
스트림은 병렬적으로 데이터를 처리할 수 있는 장점도 있습니다.
즉, 아들의 손이 여러개가 생겨 장난감을 한번에 여러개씩 담을 수 있는 현실 세계에서는 비상식적이지만
효율적인 방법이 가능하다는 것입니다!
컬렉션도 병렬처리가 가능하지만, 스스로 관리해야 하기에 비용이 많이 들어가는 작업입니다.

정리
외부 반복
- 명시적으로 컬렉션 항목을 하나씩 가져와서 처리
- 병렬성을 스스로 관리해야 한다.
내부 반복
- 작업을 투명하게 병렬로 처리할 수 있다.
- 더 최적화된 다양한 순서로 처리할 수 있다.
- filter나 map 같이 반복을 숨겨주는 연산 리스트가 미리 정의되어 있어야 한다.
- 반복을 숨겨주는 연산은 대부분 람다 표현식으로 인수를 받는다. 즉, 동작 파라미터화를 할 수 있다.
'Books > Modern Java In Action' 카테고리의 다른 글
[모던 자바 인 액션] Chapter7. 병렬 스트림 (0) | 2023.08.03 |
---|---|
[모던 자바 인 액션] Chapter5. 함수형 데이터 처리 (0) | 2023.07.31 |
[모던 자바 인 액션] Chapter4. 스트림 소개 (0) | 2023.07.26 |
[모던 자바 인 액션] Chapter3. 람다 표현식 (0) | 2023.07.25 |
[모던 자바 인 액션] Chapter3. 동작파라미터화 코드 전달하기 (0) | 2023.07.22 |