일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- spring boot
- 자바8
- head first
- 자바
- 클린코드
- 디자인 패턴
- Java in action
- Was
- Stream
- ddd
- CQRS
- 패스트캠퍼스
- Java 8 in action
- SERVLET
- Clean Code
- web
- 자바8인액션
- Java8 in action
- spring Batch
- spring
- facade pattern
- jsp
- 스트림
- Template Method Pattern
- Design Pattern
- Java8
- AWS101
- Java
- 자바의 신
- domain
- Today
- Total
주난v 개발 성장기
[자바 8인 액션] 5장. 스트림 활용 본문
필터링과 슬라이싱
- 일부 요소를 무시하거나 스트림을 주어진 크기로 축소하는 방법
1. 프레디케이트로 필터링
- 프레디 케이트(boolean을 반환하는 함수)를 인수로 받아서 일치하는 모든 요소를 포함하는 스트림을 반환
2.고유 요소 필터링
- distinct() 메서드 반환
3. 스트림 축소
- limit(n)
4. 요소 건너뛰기
- skip(n)
매핑
- 스트림은 함수를 인수로 받는 map 메서드 지원
- 함수를 적용한 결과가 새로운 요소로 매핑된다.
relationIds.stream().map(relationId -> likeCountVO(likeType, relationId, 0L))
.forEach(likeCountVOList::add);
스트림 평면화
- map, flatMap
검색과 매칭
1. 적어도 한 요소와 일치하는지 - anyMatch()
2. 모두 매칭 되는지 - allMatch()
3. 하나도 매칭이 안되는지 - noneMatch()
--> 쇼트서킷 기법, 자바의 &&, || 같은 연산을 활용한다.
모든 스트림의 요소를 처리하지 않고도 결과를 반환할 수 있다. (limit도)
요소 검색
- findAny() : 현재 스트림에서 임의의 요소를 반환, 다른 연산과 같이 사용가능
Optional<Dish> dish = menu.stream().filter(Dish::isVegetarian).findAny();
Optional이란?
- 값의 존재나 부재 여부를 표현하는 컨테이너 클래스
findAny같은 연산은 아무 요소도 반환하지 않을 수 있다.
NPE를 쉽게 발생할 수 있고, 이를 체크할 때 사용
- isPresent() 값이 있으면 true, 값이 없으면 false
첫 번째 요소 찾기
- findFirst vs findAny
두 가지 메서드가 필요한 이유는? 병렬성 때문..
병렬성 일 때 첫 번쨰 요소를 찾기는 어려우니, 병렬 시에는 findAny를 사용한다.
리듀싱
- 스트림이 작은 조각이 될 때까지 반복해서 접는 것(폴드)
1. 요소의 합
//초기값이 있는 경우
int sum = numbers.stream().reduce(0, (a,b) -> a + b);
//초기값이 없는 경우
Optional<Integer> sum = numbers.stream().reduce((a,b) -> a + b);
초기값이 없는 경우 Stream에 아무 요소가 없는 경우도 있으므로 Optional로 사용
//최대값
Optional<Integer> sum = numbers.stream().reduce(Integer::max);
//최소값
Optional<Integer> sum = numbers.stream().reduce(Integer::min);
reduce 메서드의 장점과 병렬화
단계적 반복으로 합을 구하던 방법과의 차이는?
- 내부 반복 + 병렬 처리
반복적인 합계에서는 sum 변수를 공유해야 하므로 병렬화가 어렵다.
강제로 동기화를 시킨다 하더라도 병렬로 얻은 이득이 상쇄 되버린다.
이는 7장에서 배울 포크 조인 프레임워크로 해결되지만, 현재는 가변 누적자 패턴은 병렬화와 거리가 너무 멀다.
스트림 연산 : 상태 없음과 상태 있음
지금까지 stream -> parallelStream으로 바꾸는 것만으로도 별다른 노력 없이 병렬성을 얻을 수 있었다.
map, filter등은 입력 스트림에서 요소를 받아 0또는 결과를 출력 스트림으로 보낸다.
따라서, 내부 상태를 갖지 않는 연산이다.
하지만 reduce, sum, max 같은 연산은 결과를 누적할 내부 상태가 필요하다.
이 때의 내부 상태의 크기는 한정되어 있다.
반면, sorted나 distinct는 filter나 map처럼 스트림을 입력 받아 다른 스트림으로 출력하는 것처럼 보이지만 다르다.
스트림의 요소를 정렬하거나 중복을 제거하려면 과거의 이력을 알고 있어야 한다.
또한, 이 연산을 처리하는 데 필요한 저장소 크기는 정해져있지 않다.
따라서 이러한 연산은 내부 상태를 갖는 연산으로 간주할 수 있다.
숫자형 스트림
reduce를 이용해서 요소의 합을 구할 수 있다. 이 코드는 박싱 비용이 숨어 있다.
스트림 API에서 숫자 스트림을 효율적으로 처리할 수 있도록 기본형 특화 스트림 제공
IntStream, LongStream, DoubleStream
//숫자 스트림으로 반환
int calories = menu.stream().mapToInt(Dish::getCalories).sum();
//복원
IntStream intStream = menu.stream().mapToInt(Dish::getCalories);
Stream<Integer> stream = intStream().boxed();
기본값 : OptionalInt
초기값이 있다면, 별 문제가 없지만 IntStream에서 최댓값을 찾을 때는 0이 도출 될 수 있다.
스트림에 요소가 없는 상황과 실제 최댓값이 0인 상황을 어떻게 구분할까?
OptionalInt, OptionalDouble, OptionalLong
//숫자 스트림으로 반환
OptionalInt maxCalories = menu.stream().mapToInt(Dish::getCalories).max();
int max = maxCalories.orElse(-1);
숫자 범위
1 ~ 100 처럼 특정 범위의 숫자를 생성하려 할 때, IntStream과 LongStream에서는 range, rangeClosed 두 가지 정적 메서드를 제공
range - 시작 종료값이 결과에 포함되지 않음
rangeClosed - 시작 종료값이 결과에 포함
스트림 만들기
스트림 - 데이터 처리를 표현하는 강력한 도구
//값으로 스트림 만들기
Stream<String> stream = Stream.of("Java8", "Lambdas", "In", "Action");
//배열로 스트림 만들기
int[] numbers = {2, 3, 5, 7, 11, 13}
int sum = Arrays.stream(numbers).sum();
//파일로 스트림 만들기
함수로 무한 스트림 만들기
Stream.iterator, Stream.generate
무한 스트림, 보통 무한한 값을 출력하지 않도록 limit(n)을 함께 연결해서 사용한다.
Stream.iterate(0, n -> n + 2)
.limit(10)
.forEach(System.out::println);
//supplier
Stream.generate(Match::random)
.limit(10)
.forEach(System.out::println);
요약
-
스트림 API는 복잡한 데이터 처리 질의를 표현할 수 있다,
-
filter, distinct, skip, limit로 요소를 필터링하거나 자를 수 있다.
-
map, flatMap으로 요소를 추출하거나 변환할 수 있다.
-
findFirst, findAny로 스트림 요소를 검색 할 수 있다.
-
allMatch, noneMatch, anyMatch로 프레디케이트와 일치하는 요소를 찾을 수 있다.
-
이러한 메서드는 쇼트서킷이라한다. 즉 결과를 찾는 즉시 반환하며, 전체 스트림을 처리하지 않는다.
-
reduce를 이용하여 반복 조합하며 값을 도출할 수 있다.
-
filter, map은 상태를 저장하지 않는 상태 없는 연산
-
reduce는 값을 계산하는 데 필요한 상태를 저장 --> 상태 있는 연산
-
sorted, distinct는 새로운 스트림을 반환하기에 앞서 스트림의 모든 요소를 버퍼에 저장 --> 상태 있는 연산
-
IntStream, DoubleStream, LongStream은 기본형 특화 스트림
-
무한 스트림도 생성이 가능하다.
'개발 성장기 > JAVA' 카테고리의 다른 글
[자바 8인 액션] 7장. 병렬 데이터 처리와 성능 (0) | 2020.07.26 |
---|---|
[자바 8인 액션] 6장. 스트림으로 데이터 수집 (0) | 2020.07.21 |
[자바 8인 액션] 4장. 스트림 소개 (0) | 2020.07.05 |
[자바 8인 액션] 3장. 람다 표현식 (0) | 2020.07.01 |
[자바 8 인 액션] 2장. 동작 파라미터화 코드 전달 (0) | 2020.06.17 |