스트림의 핵심은 계산을 일련의 변환으로 재구성하는 부분
각 변환 단계는 가능한 한 이전 단계의 결과를 받아서 처리하는 순수 함수여야 함
<aside> 🏷️ 순수 함수
</aside>
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);
}
텍스트 파일에서 단어별 수를 세어 빈도표로 만드는 코드
문제
forEach는 종단 연산 중 기능이 가장 적고 가장 덜 스트림 답기 때문에 계산 결과를 보고할 때만 사용하고, 계산하는 데는 사용하지 말자
(가끔은 스트림 계산 결과를 기존 컬렉션에 추가하는 등의 용도로 사용 가능)
수정된 코드
Map<String, Long> freq;
try (Stream<String> words = new Scanner(file).tokens()) {
freq = words.
collect(groupingBy(String::toLowerCase, counting()));
List<String> list = freq.keySet().stream()
.sorted(comparing(freq::get).reversed())
.limit(10)
.collect(Collectors.toList());
toMap
기본 toMap (인수 2개)
private static final Map<String, Operation> stringToEnum =
Stream.of(values()).collect(
toMap(Object::toString, e -> e)
)
각 원소가 고유한 키에 매핑되어 있을 때 사용하기 적합함 (원소 다수가 같은 키를 사용한다면 예외를 던지며 종료됨)
충돌을 다루기 위해 merge 함수를 제공할 수 있음
각 키와 해당 키의 특정 원소를 연관 짓는 맵을 생성하는 수집기 (인수 3개)
Map<Artist, Album> topHits = albums
.collect(toMap(Album:artist, a->a, maxBy(comparing(Album::sales))));
//키 충돌을 해결하기 위해 merge함수를 제공 - 두 앨범 중 sales가 더 큰 앨범을 선택
앨범 스트림을 맵으로 바꾸는데, 이 맵은 각 음악가와 그 음악가의 베스트 앨범을 짝지은 것이 됨
충돌이 나면 마지막에 쓴 값을 취하는 수집기
toMap(keyMapper, valueMapper, (oldVal, newVal) -> newVal)
groupingBy
기본 사용
words.collect(groupingBy(word -> alphabetize(word)))
다운스트림 제공
// 키: 카테고리, 값: 원소의 개수
Map<String, Long> freq = words
.collect(groupingBy(String::toLowerCase, counting()));
Map
형태로 반환하는 작업을 수행Map<String, Long>
형태로 저장