Book/이펙티브 자바
ITEM 46 스트림에는 순수 함수 사용, 수집기
이정인
2025. 5. 4. 00:18
package me.rockintuna.effectivejava.item;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.*;
import java.util.stream.Stream;
import static java.util.stream.Collectors.*;
/*
스트림에서는 부작용 없는 함수를 사용하라
*/
public class Item46 {
/*
스트림의 각 변환 단계는 순수 함수여야 한다.
순수 함수 :
오직 입력만이 결과에 영향을 주는 함수
함수 안에서 외부에 가변 참조를 하지 않아야 하며
이렇게 하려면 모든 스트림 연산에 건네는 모든 함수 객체는 부작용이 없어야 한다.
*/
public static void main(String[] args) {
/*
아래 코드는 정상적으로 동작하긴 하지만
스트림 답지 못하다. 즉, 반복문을 단순히 스트림으로 표현한 것 뿐이다.
스트림 내부에서 외부 상태 (freq 맵)을 변경하고 있다.
*/
File file = null;
Map<String, Long> freq = new HashMap<>();
try (Stream<String> words = new Scanner(file).tokens()) {
words.forEach(
word -> {
freq.merge(word.toLowerCase(), 1L, Long::sum);
}
);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
/*
변경된 아래 코드는 결과는 동일하지만 스트림 다운 진행을 보여준다.
*/
Map<String, Long> freq2;
try (Stream<String> words = new Scanner(file).tokens()) {
freq2 = words.collect(groupingBy(String::toLowerCase, counting()));
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
//스트림 팁
// forEach 연산은 스트림 연산중 가장 "덜" 스트림답다.
// forEach 연산은 스트림 계싼 결과를 보고할 때만 사용하고 계산에는 쓰지 말자.
/*
스트림에서 수집기(collector)는 collect()에서 주로 사용된다.
수집기는 스트림에서 사용될 때 스트림의 원소들을 객체 하나(일반적으로 collection)에 취합하는 역할을 한다.
스트림에서 Collection을 생성하는 수집기를 반환하는 메서드
- toList()
- toSet()
- toCollection(collectionFactory)
*/
List<String> collect = freq2.keySet().stream()
.sorted(Comparator.comparingLong(freq2::get).reversed())
.limit(10)
.collect(toList());
}
/*
스트림에서 Map을 생성하는 수집기를 반환하는 메서드
- toMap(keyMapper, valueMapper)
- toMap(keyMapper, valueMapper, mergeFunction)
- toMap(keyMapper, valueMapper, mergeFunction, mapFactory)
- toConcurrentMap(keyMapper, valueMapper)
- groupingBy(분류 함수 classifier) : 분류함수는 요소의 키를 구하는데 사용되며, Map의 value는 요소들의 List이다.
- groupingBy(분류 함수 classifier, downstream) : 추가로 downstream 수집기를 입력하면
수집기가 생성하는 맵의 value로서 요소 리스트 이외에 다른 구조, 값을 사용할 수 있다.
- groupingBy(분류 함수 classifier, mapFactory, downstream)
- groupingByConcurrent(분류 함수 classifier)
- partitioningBy(predicate) : 키가 boolean인 Map을 반환하는 수집기
downstream 전용 수집기 메서드
- counting()
- summing + Int() || Long() || Double()
- averaging + Int() || Long() || Double()
- summarizing + Int() || Long() || Double()
- ...
CharSequence 요소 전용 문자열 생성기
- joining()
- joining(delimiter)
*/
}