SlideShare a Scribd company logo
자바8 스트림 API 소개
최범균, 2013-06-03
자바 7, 6, 5, ...
int sum = 0;
int count = 0;
Collection<Employee> emps = …
for (Employee emp : emps) {
if (emp.getSalary() > 100_000_000) {
sum += emp.getSalary();
count++;
}
}
double avg = (double)sum / count;
how 중심:
employee 목록에서 개별
employee를 구해서
salary가 1억이 넘으면
sum에 salary를 더하고 개
수를 1증가
sum과 count로 평균 계산
자바 8 스트림 API
Collection<Employee> emps = …
OptionalDouble avgOpt =
emps.stream()
.filter(x -> x.getSalary() > 100)
.mapToInt(x -> x.getSalary())
.average();
double avg = avgOpt.getAsDouble();
what을 기술:
employee 중에서
salary가 100보다 큰
Employee의
salary를 구해서
평균을 구함
스트림 API: 세 단계 구성
emps.stream().filter(x -> x.getSalary() > 100).count();
스트림 생성 중개 연산 종단 연산
스트림 변환 스트림 사용
스트림 종류
● Stream<T>: 범용 스트림
● IntStream: 값 타입이 int인 스트림
● LongStream: 값 타입이 long인 스트림
● DoubleStream: 값 타입이 double인 스트림
스트림 생성
● 다양한 방식의 스트림 생성 방법 제공
o Collection: 콜렉션객체.stream()
o Files: Stream<String> Files.lines()
o BufferedReader: Stream<String> lines()
o Arrays: Arrays.stream(*)
o Random: Random.doubles(*), ints(*), longs(*)
o Stream:
 Stream.of(*)
 range(start, end), rangeClosed(start, end)
● IntStream, LongStream에서 제공
 Stream.generate(Supplier<T> s)
 Stream.iterate(T seed, UnaryOperator<T> f)
스트림 중개 연산
● 주요 중개 연산: 상태 없음
o Stream<R> map(Function<? super T, ? extends R> mapper)
 입력 T 타입 요소를 R 타입 요소로 변환한 스트림 생성
o Stream<T> filter(Predicate<? super T> predicate)
 조건을 충족하는 요소를 제공하는 새로운 스트림 생성
o Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
 T 타입 요소를 1:N의 R 타입 요소로 변환한 스트림 생성
o Stream<T> peek(Consumer<? super T> action)
 T 타입 요소를 사용만 하고, 기존 스트림을 그대로 제공하는 스트
림 생성
o Stream<T> skip(long n)
 처음 n개의 요소를 제외하는 스트림 생성
o Stream<T> limit(long maxSize)
 maxSize 까지의 요소만 제공하는 스트림 생성
o mapToInt(), mapToLong(), maptToDouble()
간단 샘플
Path path = Paths.get("src/test/resources/apache.log");
try(Stream<String> lines = Files.lines(path)) {
OptionalDouble optionalDouble = lines
.map(s -> parseApacheLog(s))
.filter(log -> log.getStatusCode() == 200)
.mapToInt(log -> log.getResponseTime())
.average();
System.out.println(
optionalDouble.isPresent() ?
optionalDouble.getAsDouble() : "none");
}
스트림 중개 연산
● 주요 중개 연산: 상태 있음
o sorted(), sorted(Comparator<T> comparator)
 정렬된 스트림을 생성
 전체 스트림의 요소를 정렬하기 때문에, 무한 스
트림에 적용할 수 없음
o distinct()
 같은 값을 갖는 요소를 중복해서 발생하지 않는
스트림 생성
스트림 종단 연산
● Stream 타입의 주요 종단 연산자
o void forEach(Consumer<? super T> con)
o long count()
o Optional<T> max(Comparator<? super T> comparator)
o Optional<T> min(Comparator<? super T> comparator)
o boolean allMatch(Predicate<? super T> predicate)
o boolean anyMatch(Predicate<? super T> predicate)
o boolean noneMatch(Predicate<? super T> predicate)
● IntStream, LongStream, DoubleStream
o sum(), min(), max()
o OptionalDouble average()
스트림 종단 연산
● reduce 연산
o Optional<T> reduce(BinaryOperator<T>
accumulator)
o T reduce(T identity, BinaryOperator<T> accumulator)
o <U> U reduce(U identity,
BiFunction<U, ? super T, U> accumulator,
BinaryOperator<U> combiner)
reduce 사용 예
// reduce(BinaryOperator<T> accumulator)
Optional<Integer> result = numbers.stream()
.reduce((x, y) -> x > y ? x : y);
// reduce(T identity, BinaryOperator<T> accu)
Integer multi = numbers.stream()
.reduce(1, (x, y) -> x * y);
// reduce(T identity, BiFunction<U, T, U> biFun, BinaryOperator<U> accu)
Double reduce = numbers.parallelStream()
.reduce(0.0,
(val1, val2) -> Double.valueOf(val1 + val2 / 10),
(val1, val2) -> val1 + val2 );
스트림 종단 연산
● collect 연산: 스트림 요소 수집
o <R, A> R collect(Collector<? super T, A, R> collector)
 T: 입력 타입, A: 결과 축적용 타입, R: 최종 타입
● Collector 인터페이스 메서드
o Supplier<A> supplier(): A 객체 생성
o BiConsumer<A, T> accumulator(): 결과 축적
o BinaryOperator<A> combiner(): 부분 결과들을 합칠 때 사용
o Function<A, R> finisher(): A를 최종 타입 R로 변환
o Set<Characteristics> characteristics(): 힌트
 CONCURRENT: 다중 쓰레드에서 실행 가능
 UNORDERED: 순서에 상관 없음
 IDENTITY_FINISH: A와 R이 같은 타입
collect 직접 구현 예…. 드럽게 복잡
List<String> names = Arrays.asList("a", "aa", "aaa", "aa", "a", "aaa", "a", "aaaa", "aaa");
Map<Integer, Integer> lengthCountMap = names.stream().collect(new Collector<String, Map<Integer, Integer>, Map<Integer, Integer>>() {
@Override public Supplier<Map<Integer, Integer>> supplier() {
return HashMap::new;
}
@Override public BiConsumer<Map<Integer, Integer>, String> accumulator() {
return (map, val) -> {
int key = val.length();
Integer count = map.get(key);
if (count == null) count = 0;
map.put(key, count + 1);
};
}
@Override public BinaryOperator<Map<Integer, Integer>> combiner() {
return (map1, map2) -> {
Map<Integer, Integer> result = new HashMap<>();
map1.forEach((k, v) -> {
if (map2.containsKey(k)) result.put(k, v + map2.get(k));
else result.put(k, v);
});
map2.forEach((k, v) -> { if (!map1.containsKey(k)) result.put(k, v); });
return result;
};
}
@Override public Function<Map<Integer, Integer>, Map<Integer, Integer>> finisher() {
return x -> x;
}
@Override public Set<Characteristics> characteristics() {
Set<Characteristics> result = new HashSet<>();
result.add(Characteristics.IDENTITY_FINISH);
result.add(Characteristics.UNORDERED);
return result;
}
});
몇 가지 Collector 구현 제공
● Collectors.toList()
o List<Employee> colMap = empList.stream()
.filter(e -> e.salary() > ONE_M).collect(toList());
● Collectors.toSet()
o Set<Integer> lengthSet = names.stream()
.map(x -> x.length()).collect(Collectors.toSet());
● Collectors.toMap()
o Map<Integer, String> lengthMap = names.stream()
.collect(Collectors.toMap(
x -> x.length(), // 요소에서 key 생성
Function.identity(), // 요소에서 value 생성
(v1, v2) -> v1 + "," + v2) // 같은 key를 갖는 값을 합침
);
몇 가지 Collector 구현 제공
● Collectors.groupingBy
o Map<String, List<Employee>> colMap = empList.stream()
.collect(groupingBy(e -> e.getLevel()));
o colMap의 key는 level, value는 같은 level 값을 가지는 Employee의 리
스트
● Collectors.partioningBy
o Map<Boolean, List<Employee>> pMap = empList.stream()
.collect(partitioningBy(e -> e.salary() > ONE_M));
o pMap의 키는 true/false, value에는 조건(salary() > ONE_M)을 충족 또
는 충족하지 않는 Employee 목록
몇 가지 Collector 구현 제공
● Collectors.summarizingInt()
o double과 long에 대한 메서드 제공
o IntSummaryStatistics stat =
intStream.collect(summarizingInt());
● XXXSummaryStatistics
o long getCount()
o XXX getSome()
o XXX getMin(), getMax()
o double getAverage()
최대한 연산 지연
● 스트림은 최대한 연산을 지연
Stream<Integer> filteredStream =
Arrays.asList(1, 2, 3, 4, 5)
.stream()
.filter(x -> x > 2);
Stream<Integer> doubledStream =
filteredStream.map(x -> x * 2);
long count = doubledStream.count();
count()를 실행할 때 까지
filter와 map을 실행하지
않음
병렬 처리
● 멀티 쓰레드로 병렬 실행 가능
int sum = numberList.parallelStream()
.filter(x -> x % 2 == 0)
.sum();
동시에 다수의 쓰레드가 filter와 sum을 실행
각 쓰레드는 filter() -> sum()을 실행하고
최종적으로 각 쓰레드의 sum() 결과를 다시 sum() 함
정리
● 스트림 처리를 위한 추상화 제공
o 스트림 생성
o 중개 연산: 필터, 맵
o 종단 연산: 결과 생성(reduce), 수집(collect), 사용
(forEach)
● 지연 연산 통한 불필요한 연산 실행 최소화
o 예, stream.filter(X::isSoldOut).limit(10)
 isSoldOut이 true인 전체 요소를 검사하지 않고,
true인 것 중에서 처음 10개까지만 검사함
● 병렬 처리 지원
o 병렬 처리에 알맞게 동작하도록 종단 연산을 구현해
야 함

More Related Content

PPTX
Grooming.pptx
PPTX
Tips on Effective Email Writing
PDF
Estrutura de dados - Implementação de filas com listas
PPT
02 ppt how to make a cv ( full)
PDF
Job Advertisement
PDF
Business Email Format
PDF
PHPUnit Cheat Sheet
PDF
Aula 04 - GP II - Avaliação de Desempenho.pdf
Grooming.pptx
Tips on Effective Email Writing
Estrutura de dados - Implementação de filas com listas
02 ppt how to make a cv ( full)
Job Advertisement
Business Email Format
PHPUnit Cheat Sheet
Aula 04 - GP II - Avaliação de Desempenho.pdf

Viewers also liked (17)

PDF
자바8 람다식 소개
PDF
간단 Ip 필터 구현 이야기
PDF
TDD 발담그기 @ 공감세미나
PDF
java 8 람다식 소개와 의미 고찰
PDF
Spring batch와 함께 하는 TDD
PDF
Java 8 api :: lambda 이용하기
PPTX
오픈소스를 활용한 Batch_처리_플랫폼_공유
PDF
keras 빨리 훑어보기(intro)
PDF
Tdd live spring camp 2013
PDF
Okjsp 13주년 발표자료: 생존 프로그래밍 Test
PDF
Spring Boot 소개
PDF
스타트업은 데이터를 어떻게 바라봐야 할까? (개정판)
PDF
세션4. 예제로 배우는 스마트 컨트랙트 프로그래밍
PDF
세션5. web3.js와 Node.js 를 사용한 dApp 개발
PDF
세션3. geth 클라이언트 실습 및 모니터링과 시각화
PDF
세션2. 이더리움 합의 알고리즘과 마이닝
PDF
세션1. block chain as a platform
자바8 람다식 소개
간단 Ip 필터 구현 이야기
TDD 발담그기 @ 공감세미나
java 8 람다식 소개와 의미 고찰
Spring batch와 함께 하는 TDD
Java 8 api :: lambda 이용하기
오픈소스를 활용한 Batch_처리_플랫폼_공유
keras 빨리 훑어보기(intro)
Tdd live spring camp 2013
Okjsp 13주년 발표자료: 생존 프로그래밍 Test
Spring Boot 소개
스타트업은 데이터를 어떻게 바라봐야 할까? (개정판)
세션4. 예제로 배우는 스마트 컨트랙트 프로그래밍
세션5. web3.js와 Node.js 를 사용한 dApp 개발
세션3. geth 클라이언트 실습 및 모니터링과 시각화
세션2. 이더리움 합의 알고리즘과 마이닝
세션1. block chain as a platform
Ad

Similar to 자바8 스트림 API 소개 (20)

PPTX
3. stream api
PDF
3주차. stream api advance
PPTX
(망작)이것이 자바다 Chap.16 스트림&병렬처리 Stream&parallel processing(java)
PDF
씹고 뜯고 맛보고 즐기는 스트림 API
PDF
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 씹고 뜯고 맛보고 즐기는 스트림 API(박용권)
PDF
자바8강의 2강. Stream API
PDF
람다, 스트림 Api
PDF
Java stream v0.1
PDF
Java stream v0.1
PPTX
스트림Api 스터디 2일
PPTX
Feel functional
PDF
Java(4/4)
PPTX
조리돌림 JAVA8 기반의 기능.pptx
PDF
Collection framework
PPTX
Java collections framework
PDF
Java8 & Lambda
PPTX
자바 8
PPTX
하둡 타입과 포맷
PDF
SpringCamp 2013 : About Jdk8
PPTX
스트림Api 소개
3. stream api
3주차. stream api advance
(망작)이것이 자바다 Chap.16 스트림&병렬처리 Stream&parallel processing(java)
씹고 뜯고 맛보고 즐기는 스트림 API
2014.07.26 KSUG와 지앤선이 함께하는 테크니컬 세미나 - 씹고 뜯고 맛보고 즐기는 스트림 API(박용권)
자바8강의 2강. Stream API
람다, 스트림 Api
Java stream v0.1
Java stream v0.1
스트림Api 스터디 2일
Feel functional
Java(4/4)
조리돌림 JAVA8 기반의 기능.pptx
Collection framework
Java collections framework
Java8 & Lambda
자바 8
하둡 타입과 포맷
SpringCamp 2013 : About Jdk8
스트림Api 소개
Ad

More from beom kyun choi (20)

PDF
옛날 웹 개발자가 잠깐 맛본 Vue.js 소개
PDF
DDD로 복잡함 다루기
PDF
DDD 준비 서문래
PDF
Tensorflow regression 텐서플로우 회귀
PDF
Ddd start 부록 지앤선&ksug
PDF
MVP 패턴 소개
PPTX
파이썬 언어 기초
PDF
도메인구현 KSUG 20151128
PDF
Event source 학습 내용 공유
PDF
모델링 연습 리뷰
PDF
ALS WS에 대한 이해 자료
PDF
Ji 개발 리뷰 (신림프로그래머)
PDF
리뷰의 기술 소개
PDF
스프링 시큐리티 구조 이해
PDF
Zookeeper 소개
PDF
하둡2 YARN 짧게 보기
PDF
차원축소 훑어보기 (PCA, SVD, NMF)
PDF
객체 지향 발담그기 JCO 컨퍼런스 14회
PDF
Storm 훑어보기
PDF
Hive 입문 발표 자료
옛날 웹 개발자가 잠깐 맛본 Vue.js 소개
DDD로 복잡함 다루기
DDD 준비 서문래
Tensorflow regression 텐서플로우 회귀
Ddd start 부록 지앤선&ksug
MVP 패턴 소개
파이썬 언어 기초
도메인구현 KSUG 20151128
Event source 학습 내용 공유
모델링 연습 리뷰
ALS WS에 대한 이해 자료
Ji 개발 리뷰 (신림프로그래머)
리뷰의 기술 소개
스프링 시큐리티 구조 이해
Zookeeper 소개
하둡2 YARN 짧게 보기
차원축소 훑어보기 (PCA, SVD, NMF)
객체 지향 발담그기 JCO 컨퍼런스 14회
Storm 훑어보기
Hive 입문 발표 자료

자바8 스트림 API 소개

  • 1. 자바8 스트림 API 소개 최범균, 2013-06-03
  • 2. 자바 7, 6, 5, ... int sum = 0; int count = 0; Collection<Employee> emps = … for (Employee emp : emps) { if (emp.getSalary() > 100_000_000) { sum += emp.getSalary(); count++; } } double avg = (double)sum / count; how 중심: employee 목록에서 개별 employee를 구해서 salary가 1억이 넘으면 sum에 salary를 더하고 개 수를 1증가 sum과 count로 평균 계산
  • 3. 자바 8 스트림 API Collection<Employee> emps = … OptionalDouble avgOpt = emps.stream() .filter(x -> x.getSalary() > 100) .mapToInt(x -> x.getSalary()) .average(); double avg = avgOpt.getAsDouble(); what을 기술: employee 중에서 salary가 100보다 큰 Employee의 salary를 구해서 평균을 구함
  • 4. 스트림 API: 세 단계 구성 emps.stream().filter(x -> x.getSalary() > 100).count(); 스트림 생성 중개 연산 종단 연산 스트림 변환 스트림 사용
  • 5. 스트림 종류 ● Stream<T>: 범용 스트림 ● IntStream: 값 타입이 int인 스트림 ● LongStream: 값 타입이 long인 스트림 ● DoubleStream: 값 타입이 double인 스트림
  • 6. 스트림 생성 ● 다양한 방식의 스트림 생성 방법 제공 o Collection: 콜렉션객체.stream() o Files: Stream<String> Files.lines() o BufferedReader: Stream<String> lines() o Arrays: Arrays.stream(*) o Random: Random.doubles(*), ints(*), longs(*) o Stream:  Stream.of(*)  range(start, end), rangeClosed(start, end) ● IntStream, LongStream에서 제공  Stream.generate(Supplier<T> s)  Stream.iterate(T seed, UnaryOperator<T> f)
  • 7. 스트림 중개 연산 ● 주요 중개 연산: 상태 없음 o Stream<R> map(Function<? super T, ? extends R> mapper)  입력 T 타입 요소를 R 타입 요소로 변환한 스트림 생성 o Stream<T> filter(Predicate<? super T> predicate)  조건을 충족하는 요소를 제공하는 새로운 스트림 생성 o Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)  T 타입 요소를 1:N의 R 타입 요소로 변환한 스트림 생성 o Stream<T> peek(Consumer<? super T> action)  T 타입 요소를 사용만 하고, 기존 스트림을 그대로 제공하는 스트 림 생성 o Stream<T> skip(long n)  처음 n개의 요소를 제외하는 스트림 생성 o Stream<T> limit(long maxSize)  maxSize 까지의 요소만 제공하는 스트림 생성 o mapToInt(), mapToLong(), maptToDouble()
  • 8. 간단 샘플 Path path = Paths.get("src/test/resources/apache.log"); try(Stream<String> lines = Files.lines(path)) { OptionalDouble optionalDouble = lines .map(s -> parseApacheLog(s)) .filter(log -> log.getStatusCode() == 200) .mapToInt(log -> log.getResponseTime()) .average(); System.out.println( optionalDouble.isPresent() ? optionalDouble.getAsDouble() : "none"); }
  • 9. 스트림 중개 연산 ● 주요 중개 연산: 상태 있음 o sorted(), sorted(Comparator<T> comparator)  정렬된 스트림을 생성  전체 스트림의 요소를 정렬하기 때문에, 무한 스 트림에 적용할 수 없음 o distinct()  같은 값을 갖는 요소를 중복해서 발생하지 않는 스트림 생성
  • 10. 스트림 종단 연산 ● Stream 타입의 주요 종단 연산자 o void forEach(Consumer<? super T> con) o long count() o Optional<T> max(Comparator<? super T> comparator) o Optional<T> min(Comparator<? super T> comparator) o boolean allMatch(Predicate<? super T> predicate) o boolean anyMatch(Predicate<? super T> predicate) o boolean noneMatch(Predicate<? super T> predicate) ● IntStream, LongStream, DoubleStream o sum(), min(), max() o OptionalDouble average()
  • 11. 스트림 종단 연산 ● reduce 연산 o Optional<T> reduce(BinaryOperator<T> accumulator) o T reduce(T identity, BinaryOperator<T> accumulator) o <U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner)
  • 12. reduce 사용 예 // reduce(BinaryOperator<T> accumulator) Optional<Integer> result = numbers.stream() .reduce((x, y) -> x > y ? x : y); // reduce(T identity, BinaryOperator<T> accu) Integer multi = numbers.stream() .reduce(1, (x, y) -> x * y); // reduce(T identity, BiFunction<U, T, U> biFun, BinaryOperator<U> accu) Double reduce = numbers.parallelStream() .reduce(0.0, (val1, val2) -> Double.valueOf(val1 + val2 / 10), (val1, val2) -> val1 + val2 );
  • 13. 스트림 종단 연산 ● collect 연산: 스트림 요소 수집 o <R, A> R collect(Collector<? super T, A, R> collector)  T: 입력 타입, A: 결과 축적용 타입, R: 최종 타입 ● Collector 인터페이스 메서드 o Supplier<A> supplier(): A 객체 생성 o BiConsumer<A, T> accumulator(): 결과 축적 o BinaryOperator<A> combiner(): 부분 결과들을 합칠 때 사용 o Function<A, R> finisher(): A를 최종 타입 R로 변환 o Set<Characteristics> characteristics(): 힌트  CONCURRENT: 다중 쓰레드에서 실행 가능  UNORDERED: 순서에 상관 없음  IDENTITY_FINISH: A와 R이 같은 타입
  • 14. collect 직접 구현 예…. 드럽게 복잡 List<String> names = Arrays.asList("a", "aa", "aaa", "aa", "a", "aaa", "a", "aaaa", "aaa"); Map<Integer, Integer> lengthCountMap = names.stream().collect(new Collector<String, Map<Integer, Integer>, Map<Integer, Integer>>() { @Override public Supplier<Map<Integer, Integer>> supplier() { return HashMap::new; } @Override public BiConsumer<Map<Integer, Integer>, String> accumulator() { return (map, val) -> { int key = val.length(); Integer count = map.get(key); if (count == null) count = 0; map.put(key, count + 1); }; } @Override public BinaryOperator<Map<Integer, Integer>> combiner() { return (map1, map2) -> { Map<Integer, Integer> result = new HashMap<>(); map1.forEach((k, v) -> { if (map2.containsKey(k)) result.put(k, v + map2.get(k)); else result.put(k, v); }); map2.forEach((k, v) -> { if (!map1.containsKey(k)) result.put(k, v); }); return result; }; } @Override public Function<Map<Integer, Integer>, Map<Integer, Integer>> finisher() { return x -> x; } @Override public Set<Characteristics> characteristics() { Set<Characteristics> result = new HashSet<>(); result.add(Characteristics.IDENTITY_FINISH); result.add(Characteristics.UNORDERED); return result; } });
  • 15. 몇 가지 Collector 구현 제공 ● Collectors.toList() o List<Employee> colMap = empList.stream() .filter(e -> e.salary() > ONE_M).collect(toList()); ● Collectors.toSet() o Set<Integer> lengthSet = names.stream() .map(x -> x.length()).collect(Collectors.toSet()); ● Collectors.toMap() o Map<Integer, String> lengthMap = names.stream() .collect(Collectors.toMap( x -> x.length(), // 요소에서 key 생성 Function.identity(), // 요소에서 value 생성 (v1, v2) -> v1 + "," + v2) // 같은 key를 갖는 값을 합침 );
  • 16. 몇 가지 Collector 구현 제공 ● Collectors.groupingBy o Map<String, List<Employee>> colMap = empList.stream() .collect(groupingBy(e -> e.getLevel())); o colMap의 key는 level, value는 같은 level 값을 가지는 Employee의 리 스트 ● Collectors.partioningBy o Map<Boolean, List<Employee>> pMap = empList.stream() .collect(partitioningBy(e -> e.salary() > ONE_M)); o pMap의 키는 true/false, value에는 조건(salary() > ONE_M)을 충족 또 는 충족하지 않는 Employee 목록
  • 17. 몇 가지 Collector 구현 제공 ● Collectors.summarizingInt() o double과 long에 대한 메서드 제공 o IntSummaryStatistics stat = intStream.collect(summarizingInt()); ● XXXSummaryStatistics o long getCount() o XXX getSome() o XXX getMin(), getMax() o double getAverage()
  • 18. 최대한 연산 지연 ● 스트림은 최대한 연산을 지연 Stream<Integer> filteredStream = Arrays.asList(1, 2, 3, 4, 5) .stream() .filter(x -> x > 2); Stream<Integer> doubledStream = filteredStream.map(x -> x * 2); long count = doubledStream.count(); count()를 실행할 때 까지 filter와 map을 실행하지 않음
  • 19. 병렬 처리 ● 멀티 쓰레드로 병렬 실행 가능 int sum = numberList.parallelStream() .filter(x -> x % 2 == 0) .sum(); 동시에 다수의 쓰레드가 filter와 sum을 실행 각 쓰레드는 filter() -> sum()을 실행하고 최종적으로 각 쓰레드의 sum() 결과를 다시 sum() 함
  • 20. 정리 ● 스트림 처리를 위한 추상화 제공 o 스트림 생성 o 중개 연산: 필터, 맵 o 종단 연산: 결과 생성(reduce), 수집(collect), 사용 (forEach) ● 지연 연산 통한 불필요한 연산 실행 최소화 o 예, stream.filter(X::isSoldOut).limit(10)  isSoldOut이 true인 전체 요소를 검사하지 않고, true인 것 중에서 처음 10개까지만 검사함 ● 병렬 처리 지원 o 병렬 처리에 알맞게 동작하도록 종단 연산을 구현해 야 함