[Java] 23. 스트림 최종연산(통계와 그룹화 및 분할)
스트림의 최종연산
에 대한 포스팅과 스트림 최종연산 중 하나인 collect() 메서드
와 Collector 인터페이스
를 통한 통계
및 그룹화(Grouping)
와 분할(partitioning)
연산에 대한 포스팅이다.
1. 스트림의 최종연산
최종 연산자는 스트림 파이프라인의 끝을 나타내며, 스트림의 요소를 소모하여 실제 결과를 반환합니다. 이 연산자가 호출되기 전까지 중간 연산은 실제로 수행되지 않습니다. 최종 연산자는 스트림을 닫는 역할을 한다.
최종 연산 | 설명 |
---|---|
void forEach(Consumer<? super T> action) void forEachOrdered(Consumer<? super T> action) | 각 요소에 지정된 작업 수행 |
long count() | 스트림의 요소의 개수 반환 |
Optional<T> max(Comparator<? super T> comparator) Optional<T> min(Comparator<? super T> comparator) | 스트림의 최대값/최소값 반환 |
Optional<T> findAny() Optional<T> findFirst() | 스트림의 요소 아무거나 하나를 반환 스트림의 첫번째 요소 하나를 반환 |
boolean allMatch(Predicate<T> p) boolean anyMatch(Predicate<T> p) boolean noneMatch(Predicate<T> p) | 모든 요소를 만족하는지 확인 하나라도 요소를 만족하는지 확인 모든 요소를 만족시키지 않는지 확인 |
Object[] toArray() A[] toArray(IntFunction<A[]> generator) | 스트림의 모든 요소를 배열로 반환 |
Optional<T> reduce(BinaryOperator<T> accumulator) T reduce(<T> identity, BinaryOperator<T> accumulator) U reduce(<U> identity, BiFunction<U,T,U> accumulator, BinaryOperator<U> combiner) | 스트림의 요소를 하나씩 줄여가면서(리듀싱) 계산 |
R collect(Collector<T,A,R> collector) R collect(Supplier<R> supplier, BiConsumer<R,T> accumulator, BiConsumer<R.R> combiner) | 주로 요소를 그룹화하거나 분할한 결과를 컬렉션으로 반환 |
◼︎ forEach()
stream.forEach()
은 중첩된 구조의 요소들을 평면화(flatten)하는 데 사용된다.
//직렬로 모든 요소에 대해 지정 된 작업을 수행
void forEach(Consumer<? super T> action)
//모든 요소에 대해 순서를 보장 된 작업을 수행, 병렬 스트림 경우 순서가 보장
void forEachOrdered(Consumer<? super T> action)
//기본 sequential() 직렬 스트림
IntStream.range(1, 10).sequential().forEach(System.out::print);
IntStream.range(1, 10).sequential().forEachOrdered(System.out::print);
//parallel() 병렬 스트림
//- forEach : 병렬 스트림 경우 순서가 보장되지 않음
IntStream.range(1, 10).parallel().forEach(System.out::print);
//- forEachOrdered : 병렬 스트림 경우 순서가 보장됨
IntStream.range(1, 10).parallel().forEachOrdered(System.out::print);
◼︎ count()
stream.count()
메서드는 해당 스트림에서 요소의 개수를 세는 데 사용된다.
//스트림의 전체 카운팅
long totCnt1 = accSubItems.stream().count();
long totCnt2 = accSubItems.stream().collect(Collectors.counting());
◼︎ min(), max()
stream.min()/max()
는 스트림의 요소 중 가장 작은 값, 큰 값을 반환한다.
- Optional<T> max(Comparator<? super T> comparator)
- Optional<T> min(Comparator<? super T> comparator)
Optional<Integer> max = numbers.stream().max(Integer::compareTo);
◼︎ match()
stream에 조건 검사 allMath(), anyMatch(), noneMatch() 와 findFirst(), findAny()
최종연산에 대한 포스팅이다.
boolean allMatch(Predicate<? super T> predicate) //모든 요소를 만족하는지 확인
boolean anyMatch(Predicate<? super T> predicate) //하나라도 요소를 만족하는지 확인
boolean noneMatch(Predicate<? super T> predicate) //모든 요소를 만족시키지 않는지 확인
boolean allPositive = numbers.stream().allMatch(num -> num > 0);
System.out.println("모든 요소가 양수인가요? " + allPositive);
boolean anyNegative = numbers.stream().anyMatch(num -> num < 0);
System.out.println("하나라도 음수인 요소가 있나요? " + anyNegative);
boolean noneZero = numbers.stream().noneMatch(num -> num == 0);
System.out.println("모든 요소가 0이 아닌가요? " + noneZero);
◼︎ find()
두 메서드 모두 Optional
을 반환하는데, 이는 스트림에서 요소를 찾지 못했을 경우에 대해서이다. findFirst()
와 findAny()
는 요소를 찾으면 해당 요소를 담은 Optional
을 반환하고, 요소가 없는 경우에는 Optional.empty()
를 반환한다.
Optional<T> findFirst() //첫번째 요소를 반환, 순차 스트림에 사용
Optional<T> findAny() //아무 요소 하나를 반환, 병렬 스트림에 사용
Optional<AccSubItem> retFirst = AccSubItems.stream()
.filter(e -> e.getAccId().startsWith("B"))
.findFirst();
System.out.println("# findFirst = " + retFirst.get()); //순차적으로 filter 조건에 맞는 "B222"만 반환
Optional<AccSubItem> retAny = AccSubItems.parallelStream()
.filter(e -> e.getAccId().startsWith("B"))
.findAny();
System.out.println("# retAny = " + retAny.get()); //병렬처리시에 filter 조건에 맞는 아무 쓰레드에서 반환
◼︎ reduce()
stream.reduce()
는 스트림의 모든 요소를 하나로 줄이는 연산을 수행합니다.
Optional<T> reduce(BinaryOperator<T> accumulator)
T reduce(T identity, BinaryOperator<T> accumulator)
U reduce(U identity, BiFunction<U,T,U> accumulator, BinaryOperator<U> combiner)
- identity : 초기값
- accumulator : 이전 연산결과와 스트림의 요소에 수행할 연산
- combiner : 병렬처리된 결과를 합치는데 사용할 연산(병렬 스트림)
- [Java] Stream Reduce 최종연산
//T reduce(T identity, BinaryOperator<T> accumulator)
int count = numbers.stream().reduce(0, (a, b) -> a+1);
System.out.println("# count : " + count);
int sum = numbers.stream().reduce(0, (a, b) -> a+b);
System.out.println("# sum : " + sum);
int min = numbers.stream().reduce(Integer.MAX_VALUE, (a, b) -> a<b ? a:b);
System.out.println("# min : " + min);
int max = numbers.stream().reduce(Integer.MIN_VALUE, (a, b) -> a>b ? a:b);
System.out.println("# max : " + max);
//Optional<T> reduce(BinaryOperator<T> accumulator)
Optional<Integer> optMin = numbers.stream().reduce(Integer::min);
System.out.println("# optMin : " + optMin.get());
Optional<Integer> optMax = numbers.stream().reduce(Integer::max);
System.out.println("# optMax : " + optMax.get());
1-1. 스트림의 컬렉션 변환
◼︎ collect()
Collector 인터페이스는 스트림의 collect() 메서드
와 함께 사용되며, 스트림의 요소를 여러 그룹으로 분할하거나, 요소들을 리스트, 세트, 맵 등의 컬렉션으로 수집하고, 통계 수치를 계산하는 등의 기능을 수행합니다.
◼︎ toList()
// Collectors.toList()를 사용하여 List로 수집
List<AccSubItem2> collectedToList = accSubItems.stream()
.collect(Collectors.toList());
◼︎ toSet()
// Collectors.toSet()를 사용하여 Set으로 수집
Set<AccSubItem2> collectedToSet = accSubItems.stream()
.collect(Collectors.toSet());
◼︎ toMap()
// Collectors.toMap()를 사용하여 Map으로 수집 (AccId 를 key로 사용)
// Key duplication 오류로 toMap() 사용 시 mergeFunction 지정
// -> (existing, replacement) -> existing 부분은 중복 키가 발생했을 때 기존 값(existing)을 유지하는 방법
Map<String, AccSubItem2> collectedToMap = accSubItems.stream()
.collect(Collectors.toMap(AccSubItem2::getAccId, item -> item, (existing, replacement) -> existing));
◼︎ toArray()
// toArray 를 활용해 List 를 Array 형태로 변환
AccSubItem2[] collectedToArray = accSubItems.stream().toArray(AccSubItem2[]::new);
1-2. 스트림의 통계
◼︎ counting() : 전체 건수 구하기
//스트림의 전체 카운팅
long totCnt1 = accSubItems.stream().count();
long totCnt2 = accSubItems.stream().collect(Collectors.counting());
System.out.println("# 1 .totCnt1 = " + totCnt1 + ", totCnt2 = " + totCnt2);
# 1 .totCnt1 = 10, totCnt2 = 10
◼︎ summingInt() : 합계 구하기
//int 형 전체 합계 점수
int sumScore1 = accSubItems.stream().mapToInt(AccSubItem2::getScore).sum();
int sumScore2 = accSubItems.stream().collect(Collectors.summingInt(AccSubItem2::getScore));
System.out.println("# 2. sumScore1 = " + sumScore1 + ", sumScore2 = " + sumScore2);
# 2. sumScore1 = 5950, sumScore2 = 5950
◼︎ reducing() : reduce 로 BigDecimal 합계 구하기
//BigDecimal 형 데이터 전체 합계 금액은 reduce() 로 구하기 예제
BigDecimal sumAmt1 = accSubItems.stream()
.map(AccSubItem2::getAccAmt)
.reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal sumAmt2 = accSubItems.stream()
.map(AccSubItem2::getAccAmt)
.collect(Collectors.reducing(BigDecimal.ZERO, BigDecimal::add));
System.out.println("# 3. sumAmt1 = " + sumAmt1);
System.out.println("# sumAmt2 = " + sumAmt2);
# 3. sumAmt1 = 945346
# sumAmt2 = 945346
◼︎ min(), max() : 최소, 최대 값 구하기
//mapToInt(Integer) , mapToLong(Long) 타입 min, max 구하기
OptionalInt minScore = accSubItems.stream()
.mapToInt(AccSubItem2::getScore)
.min();
OptionalInt maxScore = accSubItems.stream()
.mapToInt(AccSubItem2::getScore)
.max();
System.out.println("# 4. minScore = " + minScore.getAsInt() + ", maxScore = " + maxScore.getAsInt());
# 4. minScore = 120, maxScore = 900
◼︎ min(), max() 에 Comparator.comparingInt() 활용
//AccSubItem 객체 중에 score 점수기준으로 min, max 객체 구하기
Optional<AccSubItem2> minAccSubItem = accSubItems.stream()
.min(Comparator.comparingInt(AccSubItem2::getScore));
Optional<AccSubItem2> maxAccSubItem = accSubItems.stream()
.max(Comparator.comparingInt(AccSubItem2::getScore));
System.out.println("# 5. minAccSubItem = " + minAccSubItem);
System.out.println(" maxAccSubItem = " + maxAccSubItem);
# 5. minAccSubItem = Optional[AccSubItem2{accId='A123', depWdrTypCd='10', accAmt=100000, score=120}]
maxAccSubItem = Optional[AccSubItem2{accId='A222', depWdrTypCd='20', accAmt=1000, score=900}]
◼︎ minBy(), maxBy() 에 Comparator.comparing() 활용
//accAmt 변수 그룹 기준으로 min, max 객체 구하기
Optional<AccSubItem2> minByDepWdrTypCd = accSubItems.stream()
.collect(Collectors.minBy(Comparator.comparing(AccSubItem2::getAccAmt)));
Optional<AccSubItem2> maxByDepWdrTypCd = accSubItems.stream()
.collect(Collectors.maxBy(Comparator.comparing(AccSubItem2::getAccAmt)));
System.out.println("# 6. minByDepWdrTypCd = " + minByDepWdrTypCd);
System.out.println(" maxByDepWdrTypCd = " + maxByDepWdrTypCd);
# 6. minByDepWdrTypCd = Optional[AccSubItem2{accId='A222', depWdrTypCd='20', accAmt=1000, score=900}]
maxByDepWdrTypCd = Optional[AccSubItem2{accId='A610', depWdrTypCd='20', accAmt=431000, score=510}]
◼︎ averagingInt() : 평균 구하기
// 7. score를 기준으로 평균 계산하여 출력
Double averageScore = accSubItems.stream()
.collect(Collectors.averagingInt(AccSubItem2::getScore));
System.out.println("# 7. Score 의 평균 = " + averageScore);
# 7. Score 의 평균 = 595.0
1-3. 스트림 문자열 결합
◼︎ joining()
String joiningStr = accSubItems.stream().map(AccSubItem2::getAccId).collect(Collectors.joining());
System.out.println("# joiningStr1 = " + joiningStr);
joiningStr = accSubItems.stream().map(AccSubItem2::getAccId).collect(Collectors.joining("|"));
System.out.println("# joiningStr2 = " + joiningStr);
joiningStr =accSubItems.stream().map(AccSubItem2::getAccId).collect(Collectors.joining(",", "{", "}"));
System.out.println("# joiningStr3 = " + joiningStr);
# joiningStr1 = A123A123A123A201A222A510A510A510A610A105
# joiningStr2 = A123|A123|A123|A201|A222|A510|A510|A510|A610|A105
# joiningStr3 = {A123,A123,A123,A201,A222,A510,A510,A510,A610,A105}
1-4. 스트림 GroupingBy 그룹 연산
Collectors.groupingBy()
는 스트림 요소를 지정된 기준에 따라 그룹화하는 기능으로 이를 통해 데이터를 그룹별로 분류하고 집계할 수 있다.
Collector groupingBy(Function classifier)
Collector groupingBy(Function classifier, Collector downstream)
Collector groupingBy(Function classifier, Supplier mapFactory, Collector downstream)
◼︎ groupingBy 기본 예제
// DepWdrTypCd 멤버변수 기준으로 groupBy 별 건수
Map<String, Long> accSubGroupByCnt = accSubItems.stream()
.collect(Collectors.groupingBy(AccSubItem2::getDepWdrTypCd, Collectors.counting()));
System.out.println("DepWdrTypCd 멤버변수 기준으로 groupBy 별 건수: " + accSubGroupByCnt);
// DepWdrTypCd 멤버변수 기준으로 groupBy 별로 객체 List
Map<String, List<AccSubItem2>> accSubGroupByMap = accSubItems.stream()
.collect(Collectors.groupingBy(AccSubItem2::getDepWdrTypCd));
accSubGroupByMap.get("10").forEach(accSubItem -> {
System.out.println("[10]" + accSubItem.toString());
});
accSubGroupByMap.get("20").forEach(accSubItem -> {
System.out.println("[20]" + accSubItem.toString());
});
DepWdrTypCd 멤버변수 기준으로 groupBy 별 건수: {20=3, 10=7}
[10]AccSubItem2{accId='A123', depWdrTypCd='10', accAmt=11000, score=700}
[10]AccSubItem2{accId='A123', depWdrTypCd='10', accAmt=4000, score=120}
[10]AccSubItem2{accId='A201', depWdrTypCd='10', accAmt=128000, score=320}
[10]AccSubItem2{accId='A510', depWdrTypCd='10', accAmt=21000, score=820}
[10]AccSubItem2{accId='A510', depWdrTypCd='10', accAmt=37000, score=790}
[10]AccSubItem2{accId='A510', depWdrTypCd='10', accAmt=432000, score=240}
[10]AccSubItem2{accId='A105', depWdrTypCd='10', accAmt=12346, score=880}
[20]AccSubItem2{accId='A123', depWdrTypCd='20', accAmt=103000, score=670}
[20]AccSubItem2{accId='A222', depWdrTypCd='20', accAmt=100000, score=900}
[20]AccSubItem2{accId='A610', depWdrTypCd='20', accAmt=431000, score=510}
◼︎ groupingBy n분할 일반적인 그룹화
그룹화 된 그룹명이 정렬 되지 않은 상태이다.
// n분할 그룹화
Map<String, List<AccSubItem2>> gradeGroupBy = accSubItems.stream()
.collect(Collectors.groupingBy(
accSubItem -> {
if (accSubItem.getScore() >= 900) return "A 등급";
else if (accSubItem.getScore() >= 800) return "B 등급";
else if (accSubItem.getScore() >= 700) return "C 등급";
else return "D 등급";
}
));
System.out.println("========== 일반적인 n분할 그룹화 ==========");
gradeGroupBy.forEach((key, accSubItem) -> {
System.out.println("[" + key + "]");
accSubItem.forEach(System.out::println);
});
========== 일반적인 n분할 그룹화 ==========
[C 등급]
AccSubItem2{accId='A123', depWdrTypCd='10', accAmt=11000, score=700}
AccSubItem2{accId='A510', depWdrTypCd='10', accAmt=37000, score=790}
[D 등급]
AccSubItem2{accId='A123', depWdrTypCd='10', accAmt=4000, score=120}
AccSubItem2{accId='A123', depWdrTypCd='20', accAmt=103000, score=670}
AccSubItem2{accId='A201', depWdrTypCd='10', accAmt=128000, score=320}
AccSubItem2{accId='A510', depWdrTypCd='10', accAmt=432000, score=240}
AccSubItem2{accId='A610', depWdrTypCd='20', accAmt=431000, score=510}
[B 등급]
AccSubItem2{accId='A510', depWdrTypCd='10', accAmt=21000, score=820}
AccSubItem2{accId='A105', depWdrTypCd='10', accAmt=12346, score=880}
[A 등급]
AccSubItem2{accId='A222', depWdrTypCd='20', accAmt=100000, score=900}
◼︎ groupingBy n분할 정렬/역정렬 그룹화
TreeMap 을 활용한 정렬/역정렬 grouping 예제이다.
TreeMap<String, List<AccSubItem2>> orderGradeGroupBy = accSubItems.stream()
.collect(Collectors.groupingBy(
accSubItem -> {
if (accSubItem.getScore() >= 900) return "A 등급";
else if (accSubItem.getScore() >= 800) return "B 등급";
else if (accSubItem.getScore() >= 700) return "C 등급";
else return "D 등급";
}
, TreeMap::new //A등급, B등급, C등급, D등급
, Collectors.toList()
)
);
System.out.println("========== 정렬 n분할 그룹화 ==========");
orderGradeGroupBy.forEach((key, accSubItem) -> {
System.out.println("[정렬][" + key + "]");
accSubItem.forEach(System.out::println);
});
System.out.println("========== 정렬 역순 n분할 그룹화 ==========");
orderGradeGroupBy.descendingMap().forEach((key, accSubItem) -> {
System.out.println("[정렬 역순][" + key + "]");
accSubItem.forEach(System.out::println);
});
========== 정렬 n분할 그룹화 ==========
[정렬][A 등급]
AccSubItem2{accId='A222', depWdrTypCd='20', accAmt=100000, score=900}
[정렬][B 등급]
AccSubItem2{accId='A510', depWdrTypCd='10', accAmt=21000, score=820}
AccSubItem2{accId='A105', depWdrTypCd='10', accAmt=12346, score=880}
[정렬][C 등급]
AccSubItem2{accId='A123', depWdrTypCd='10', accAmt=11000, score=700}
AccSubItem2{accId='A510', depWdrTypCd='10', accAmt=37000, score=790}
[정렬][D 등급]
AccSubItem2{accId='A123', depWdrTypCd='10', accAmt=4000, score=120}
AccSubItem2{accId='A123', depWdrTypCd='20', accAmt=103000, score=670}
AccSubItem2{accId='A201', depWdrTypCd='10', accAmt=128000, score=320}
AccSubItem2{accId='A510', depWdrTypCd='10', accAmt=432000, score=240}
AccSubItem2{accId='A610', depWdrTypCd='20', accAmt=431000, score=510}
========== 정렬 역순 n분할 그룹화 ==========
[정렬 역순][D 등급]
AccSubItem2{accId='A123', depWdrTypCd='10', accAmt=4000, score=120}
AccSubItem2{accId='A123', depWdrTypCd='20', accAmt=103000, score=670}
AccSubItem2{accId='A201', depWdrTypCd='10', accAmt=128000, score=320}
AccSubItem2{accId='A510', depWdrTypCd='10', accAmt=432000, score=240}
AccSubItem2{accId='A610', depWdrTypCd='20', accAmt=431000, score=510}
[정렬 역순][C 등급]
AccSubItem2{accId='A123', depWdrTypCd='10', accAmt=11000, score=700}
AccSubItem2{accId='A510', depWdrTypCd='10', accAmt=37000, score=790}
[정렬 역순][B 등급]
AccSubItem2{accId='A510', depWdrTypCd='10', accAmt=21000, score=820}
AccSubItem2{accId='A105', depWdrTypCd='10', accAmt=12346, score=880}
[정렬 역순][A 등급]
AccSubItem2{accId='A222', depWdrTypCd='20', accAmt=100000, score=900}
◼︎ groupingBy n분할 통계
TreeMap<String, Long> orderGradeGroupByCnt = accSubItems.stream()
.collect(Collectors.groupingBy(
accSubItem -> {
if (accSubItem.getScore() >= 900) return "A 등급";
else if (accSubItem.getScore() >= 800) return "B 등급";
else if (accSubItem.getScore() >= 700) return "C 등급";
else return "D 등급";
}
, TreeMap::new //A등급, B등급, C등급, D등급
, Collectors.counting()
)
);
System.out.println("========== 정렬 n분할 그룹화 통계 ==========");
orderGradeGroupByCnt.forEach((key, groupCnt) -> {
System.out.println("[" + key + "] cnt : " + groupCnt);
});
========== 정렬 n분할 그룹화 통계 ==========
[A 등급] cnt : 1
[B 등급] cnt : 2
[C 등급] cnt : 2
[D 등급] cnt : 5
◼︎ groupingBy 다중 분할(DepWdrTypCd, Score)
TreeMap<String, Map<String, List<AccSubItem2>>> multiGroupBy = accSubItems.stream()
.collect(Collectors.groupingBy(
AccSubItem2::getDepWdrTypCd, TreeMap::new, Collectors.groupingBy(
accSubItem -> {
if (accSubItem.getScore() >= 900) return "A 등급";
else if (accSubItem.getScore() >= 800) return "B 등급";
else if (accSubItem.getScore() >= 700) return "C 등급";
else return "D 등급";
}, TreeMap::new, Collectors.toList()
)
));
System.out.println("========== 다중 분할(DepWdrTypCd, Score) 그룹화 ==========");
multiGroupBy.forEach((depWdrKey, scoreGroup) -> {
System.out.println("# DepWdrTypCd: " + depWdrKey);
scoreGroup.forEach((scoreKey, items) -> {
System.out.println("\tScore: " + scoreKey);
items.forEach(e-> System.out.println(" - " + e));
});
});
========== 다중 분할(DepWdrTypCd, Score) 그룹화 ==========
# DepWdrTypCd: 10
Score: B 등급
- AccSubItem2{accId='A510', depWdrTypCd='10', accAmt=21000, score=820}
- AccSubItem2{accId='A105', depWdrTypCd='10', accAmt=12346, score=880}
Score: C 등급
- AccSubItem2{accId='A123', depWdrTypCd='10', accAmt=11000, score=700}
- AccSubItem2{accId='A510', depWdrTypCd='10', accAmt=37000, score=790}
Score: D 등급
- AccSubItem2{accId='A123', depWdrTypCd='10', accAmt=4000, score=120}
- AccSubItem2{accId='A201', depWdrTypCd='10', accAmt=128000, score=320}
- AccSubItem2{accId='A510', depWdrTypCd='10', accAmt=432000, score=240}
# DepWdrTypCd: 20
Score: A 등급
- AccSubItem2{accId='A222', depWdrTypCd='20', accAmt=100000, score=900}
Score: D 등급
- AccSubItem2{accId='A123', depWdrTypCd='20', accAmt=103000, score=670}
- AccSubItem2{accId='A610', depWdrTypCd='20', accAmt=431000, score=510}
1-5. 스트림 PartitioningBy 분할 연산
Collectors.partitioningBy()
은 요소들을 참(true)인 그룹과 거짓(false)인 boolean 그룹으로 분할해서 두 개의 그룹을 맵(Map)으로 반환한다. partitioningBy 는 2분할로 Key가 boolean 으로 true, false
이다.
Collector partitioningBy(Predicate predicate)
Collector partitioningBy(Predicate predicate, Collector downStream)
◼︎ partitioningBy 분할
//DepWdrTypCd "10"과 "20"으로 partitioningBy 분할
Map<Boolean, List<AccSubItem2>> partitioningBy = accSubItems.stream()
.collect(Collectors.partitioningBy(item -> "10".equals(item.getDepWdrTypCd())));
System.out.println("# partitioningBy");
System.out.println("- DepWdrTypCd(10) : " + partitioningBy.get(true));
System.out.println("- DepWdrTypCd(20) : " + partitioningBy.get(false));
# partitioningBy
- DepWdrTypCd(10) : [AccSubItem2{accId='A123', depWdrTypCd='10', accAmt=11000, score=700}, AccSubItem2{accId='A123', depWdrTypCd='10', accAmt=4000, score=120}, AccSubItem2{accId='A201', depWdrTypCd='10', accAmt=128000, score=320}, AccSubItem2{accId='A510', depWdrTypCd='10', accAmt=21000, score=820}, AccSubItem2{accId='A510', depWdrTypCd='10', accAmt=37000, score=790}, AccSubItem2{accId='A510', depWdrTypCd='10', accAmt=432000, score=240}, AccSubItem2{accId='A105', depWdrTypCd='10', accAmt=12346, score=880}]
- DepWdrTypCd(20) : [AccSubItem2{accId='A123', depWdrTypCd='20', accAmt=103000, score=670}, AccSubItem2{accId='A222', depWdrTypCd='20', accAmt=100000, score=900}, AccSubItem2{accId='A610', depWdrTypCd='20', accAmt=431000, score=510}]
◼︎ partitioningBy 통계
//DepWdrTypCd "10"과 "20"으로 partitioningBy 통계
Map<Boolean, Long> partitioningByCnt = accSubItems.stream()
.collect(Collectors.partitioningBy(item -> "10".equals(item.getDepWdrTypCd()), Collectors.counting()));
System.out.println("# partitioningByCnt");
System.out.println("- DepWdrTypCd(10) Cnt : " + partitioningByCnt.get(true));
System.out.println("- DepWdrTypCd(20) Cnt : " + partitioningByCnt.get(false));
# partitioningByCnt
- DepWdrTypCd(10) Cnt : 7
- DepWdrTypCd(20) Cnt : 3
◼︎ partitioningBy 분할 + 통계(min)
//DepWdrTypCd "10"과 "20"으로 partitioningBy 통계 Integer 형 Min Max
Map<Boolean, Optional<AccSubItem2>> partitioningByMin = accSubItems.stream()
.collect(Collectors.partitioningBy(
item -> "10".equals(item.getDepWdrTypCd())
, Collectors.minBy(Comparator.comparingInt(AccSubItem2::getScore))
));
System.out.println("# partitioningBy Integer Min");
System.out.println("- DepWdrTypCd(10) By Score Min : " + partitioningByMin.get(true));
System.out.println("- DepWdrTypCd(20) By Score Min : " + partitioningByMin.get(false));
# partitioningBy Integer Min
- DepWdrTypCd(10) By Score Min : Optional[AccSubItem2{accId='A123', depWdrTypCd='10', accAmt=4000, score=120}]
- DepWdrTypCd(20) By Score Min : Optional[AccSubItem2{accId='A610', depWdrTypCd='20', accAmt=431000, score=510}]
◼︎ partitioningBy 분할 + 통계(max)
//DepWdrTypCd "10"과 "20"으로 partitioningBy 통계 BigDecimal 형 Min Max
Map<Boolean, Optional<AccSubItem2>> partitioningByMax = accSubItems.stream()
.collect(Collectors.partitioningBy(
item -> "10".equals(item.getDepWdrTypCd()),
Collectors.maxBy(Comparator.comparing(AccSubItem2::getAccAmt))
));
System.out.println("# partitioningBy BigDecimal Max");
System.out.println("- DepWdrTypCd(10) By AccAmt Max : " + partitioningByMax.get(true));
System.out.println("- DepWdrTypCd(20) By AccAmt Max : " + partitioningByMax.get(false));
# partitioningBy BigDecimal Max
- DepWdrTypCd(10) By AccAmt Max : Optional[AccSubItem2{accId='A510', depWdrTypCd='10', accAmt=432000, score=240}]
- DepWdrTypCd(20) By AccAmt Max : Optional[AccSubItem2{accId='A610', depWdrTypCd='20', accAmt=431000, score=510}]
◼︎ partitioningBy 다중 분할
//DepWdrTypCd "10"과 "20" 와 AccAmt 100000 이상 partitioningBy 다중 분할
Map<Boolean, Map<Boolean, List<AccSubItem2>>> partitionInPartitioningBy = accSubItems.stream()
.collect(
Collectors.partitioningBy(item -> "10".equals(item.getDepWdrTypCd())
, Collectors.partitioningBy(item -> item.getAccAmt().compareTo(new BigDecimal(100000)) >= 0)
));
System.out.println("# partition In PartitioningBy ");
System.out.println("- DepWdrTypCd(10) By 100000 이상 By : " + partitionInPartitioningBy.get(true).get(true));
System.out.println("- DepWdrTypCd(20) By 100000 이상 By : " + partitionInPartitioningBy.get(false).get(true));
# partition In PartitioningBy
- DepWdrTypCd(10) By 100000 이상 By : [AccSubItem2{accId='A201', depWdrTypCd='10', accAmt=128000, score=320}, AccSubItem2{accId='A510', depWdrTypCd='10', accAmt=432000, score=240}]
- DepWdrTypCd(20) By 100000 이상 By : [AccSubItem2{accId='A123', depWdrTypCd='20', accAmt=103000, score=670}, AccSubItem2{accId='A222', depWdrTypCd='20', accAmt=100000, score=900}, AccSubItem2{accId='A610', depWdrTypCd='20', accAmt=431000, score=510}]
[출처]
- 자바의정석 (저자: 남궁성)