통화별로 트랜잭션을 그룹화한 코드
List<Transaction> transactions = Arrays.asList(
new Transaction(),
new Transaction(),
new Transaction()
);
Map<Currency, List<Transaction>> transactionsByCurrencies = new HashMap<>();
for (Transaction transaction : transactions){
Currency currency = transaction.getCurrency();
List<Transacion> transactionsForCurrency = transactionsByCurrencies.get(currency);
if (transactionsForCurrency == null) {
transactionsForCurrency = new ArrayList<>();
transactionsByCurrencies.put(currency, transactionsForCurrency);
}
transactionsForCurrency.add(transaction);
}
->
May<Currency, List<Transaction>> transactionsByCurrencies = transactions.stream()
.collect(groupingBy(Transaction::getCurrency));
- 198 ~ 199p
여기서는 groupingBy를 이용해서 '각 키 (통화) 버킷 그리고 각 키 버킷에 대응하는 요소 리스트를 값으로 포함하는 맵을 만들라'는 동작을 수행한다.
- 199p
counting 메서드
long howManyDishes = menu.stream().collect(Collectors.counting());
최댓값과 최솟값 검색
Comparator<Dish> dishCaloriesComparator = Comparator.comparingInt(Dish::getCalories);
Optoinal<Dish> mostCalorieDish = menu.stream().collect(mayBy(dishCaloriesComparator));
- 202p
요약 연산
int totalCalroeis = menu.stream().collect(summingInt(Dish::getCalories));
칼로리로 매핑된 각 요리의 값을 탐색하면서 초깃값(여기서는 0)으로 설정되어 있는 누적자에 칼로리를 더한다.
- 203p
IntSummaryStatistics menuStatistics = menu.stream().collect(summarizingInt(Dish::getCalories));
- 204p
문자열 연결
String shortMenu = menu.stream().collect(joining());
String shortMenu = menu.stream().map(Dish::getName).collect(joining(", "));
- 204p
리듀싱 요약 연산
int totalCalories = menu.stream().collect(reducing(0, Dish::getCalories, (i, j) -> i + j));
reducing은 인수 세 개를 받는다.
- 첫 번째 인수는 리듀싱 연산의 시작값이거나 스트림에 인수가 없을 때의 반환값
- 두 번째 인수는 칼로리 정수로 변환할 때 사용한 반환값
- 세 번째 인수는 같은 종류의 두 항목을 하나의 값으로 더하는 BinarayOperator
Optional<Dish> mostCalorieDish = menu.stream().collect(reducing( (d1, d2) -> d1.getCalories() > d2.getCalories() ? d1 : d2) );
- 206p
카운팅을 제네릭으로 구현
public static <T> Collector<T, ?, Log> counting(){
return reducing(0L, e->1L, Long::sum);
}
- 208p
Collectors의 groupingBy를 이용한 그룹핑
Map<Dish.Type, List<Dish>> dishesByType =
menu.stream().collect(groupingBy(Dish::getType));
스트림 -> 분류함수 -> 그룹핑하여 맵핑
public enum CaloricLevel { DIET, NORMAL, FAT }
Map<Caloriclevel, List<Dish>> dishesByCaloriclevel = menu.stream().collect(
groupingBy(dish -> {
if (dish.getCalories() <= 400) retrun CaloricLevel.DIET;
else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;
else return CaloricLevel.FAT;
}
));
- 210 ~ 211p
다 수준 그룹화
Map<Dish.TYPE, Map<CaloricLevel, List<Dish>>> dishesByTypeCaloricLevel =
menu.stream().collect(
groupingBy(Dish::getType, // 첫 번째 수준의 분류
groupingBy(dish -> { // 두 번째 수준의 분류
if (dish.getcalories() <= 400) return CaloricLevel.DIET;
else if (dish.getcalories() <= 700) return CaloricLevel.NORMAL;
else return CaloricLevel.FAT;
})
)
);
- 214p
분류하고 연산 하기
May<Dish.TYPE, Dish> mostCaloricByType =
menu.stream()
.collect(groupingBy(Dish::getType, // 분류
collectingAndThem(
maxBy(comparingInt(Dish::getCalories)), // 연산
Optional::get))); // 반환
partioning => 불리언 값으 리턴하는 분할
Map<Boolean, List<Dish>> partitionedMenu = menu.stream().collect(partioningBy(Dish::isVegetarian));
- 220p
stream을 이용한 소수 판단하기
public boolean isPrime(int candidate) {
// 2부터 candidate 미만 자연수를 생성한다
// 스트림의 모든 정수를 candidate로 나눌 수 없으면 true를 반환한다.
return IntStream.range(2, candidate).noneMatch(i -> candidate % i == 0);
}
public boolean isPrime2(int candidate){
// 제곱근 이하로 수를 제한하기
int candidateRoot = (int) Math.sqrt( (double) candidate);
return IntStream.rangeClosed(2, candidateRoot).noneMatch(i -> candidate % i ==0);
}
public Map<Boolean, List<Integer>> partitionPrimes(int n){
// 파티셔닝을 이용해 소수와 비소수를 구분한다.
return IntStream.rangeClosed(2, n).boxed().collect(partitioningBy(candidate -> isPrime(candidate)));
}
- 222p
성능 개선하기
isPrime 메서드로 중간 결과 리스트를 전달하기
public static boolean isPrime(List<Integer> primes, int candidate) {
return primes.stream().noneMatch(i -> candidate % i == 0);
}
제곱근 보다 작은 소수만 사용하도록 최적화하기
-> 정렬된 리스트와 프레디케이트를 인수로 받아 리스트의 첫 요소에서 시작해서 프레디케이트를 만족하는 가장 긴 요소로 이루어진 리스트를 반환하는 takeWhile이라는 메서드를 구현한다.
public static boolean isPrime(List<Integer> primes, int candidate) {
int candidateRoot = (int) Math.sqrt( (double) candidate);
return primes.stream()
.takeWhile(i -> i<=candidateRoot)
.noneMatch(i -> candidate % i == 0);
}
- 233p
'Book' 카테고리의 다른 글
[독서 기록] 모던 자바 인 액션 8장 컬렉션 API 개선 (0) | 2023.01.09 |
---|---|
[독서 기록] 모던 자바 인 액션 7장 병렬 데이터 처리와 성능 (0) | 2023.01.09 |
[독서 기록] 모던 자바 인 액션 4장 스트림 소개, 5장 스트림 활용 (0) | 2023.01.08 |
[독서 기록] 모던 자바 인 액션 3장 람다 표현식 (1) | 2023.01.06 |
[독서 기록] 모던 자바 인 액션 2장 - 동작 파라미터화 코드 전달하기 (0) | 2023.01.04 |