[Effective Java] 7 - item46 스트림에서는 부작용 없는 함수를 사용하라.
스트림은 함수형 프로그래밍에 기초한 패러다임이다. 핵심은 계산을 일련의 변환으로 재구성하는 부분이고, 각 변환 단계는 이전 단계의 결과를 받아 처리하는 함수여야 한다.
이 패러다임을 준수하기 위해forEach
연산은 스트림 계산 결과를 보고할 때만 이용하고, 계산에는 사용하지 않는 것이 좋다.
그럼 무엇을 사용해야 하나요… -> 부작용이 발생하지 않는 함수인 수집기(collector) 를 사용하자.
수집기 (Collector)
java.util.stream.Collectors
클래스 이하에 존재한다.
/**
* Implementations of {@link Collector} that implement various useful reduction
* operations, such as accumulating elements into collections, summarizing * elements according to various criteria, etc. *
* **/
해당 클래스 내에서 다양한 축소 전략을 제공하는 것을 확인할 수 있다. 이러한 전략들을 사용해, 스트림의 원소를 컬렉션으로 취합할 수 있다.
public class FrequencyTest {
public static void main(String[] args) {
// 예시 문장
String exampleSentence = "This is an example sentence to demonstrate word frequency count. This sentence contains some words, and some words are repeated.";
// 단어 빈도수 계산
Map<String, Long> freq;
try (Stream<String> words = Arrays.stream(exampleSentence.split("\\s+"))) {
freq = words
.collect(Collectors.groupingBy(String::toLowerCase, Collectors.counting()));
}
// 상위 10개 단어 추출
List<String> topTen = freq.keySet().stream() // freq 맵의 키들을 스트림으로 가져옴
.sorted(Comparator.comparing(freq::get).reversed()) // 해당 키들을 빈도수에 따라 내림차순으로 정렬
.limit(10) // 상위 10개의 요소로 제한
.collect(Collectors.toList()); // 리스트로 변환
// 출력
System.out.println("Top Ten Words:");
for (String word : topTen) {
System.out.println(word + ": " + freq.get(word));
}
}
}
위 코드는 Collectors.toList()
수집기를 이용해 단어의 빈도수를 컬렉션으로 수집하였다.
해당 코드의 출력 결과는 다음과 같다.
Map
객체로 수집할 수도 있다.
toMap
// 스트림의 각 원소가 고유한 키에 매핑되어 있을 때,
// 아래와 같은 가장 기본적인 toMap 수집기를 이용할 수 있다.
Map<String, Operation> stringToEnum =
Stream.of(values()).collect(toMap(Object::toString, e -> e));
// 아래와 같은 toMap 수집기는 각 키와 해당 키의 특정 원소를 연관 짓는 맵을 필요로 할 때 유용하다.
Map<Artist, Album> topHits = albums.collect(
toMap(Album::artist, a->a, maxBy(comparing(Album::sales))));
// 인수가 3개인 toMap은 충돌이 나면 마지막 값을 취하는 Collector를 만들 때 유용하다.
toMap(keyMapper, valueMapper, (oldVal, newVal) -> newVal)
스트림의 각 원소가 고유한 키 역할을 할때 적합하다.
groupingBy
입력으로 분류 함수(classifier)를 받고 원소들을 카테고리 별로 모아놓은 맵을 담은 수집기를 반환한다. classifier는 원소를 입력받아 원소가 속하는 카테고리를 반환하고, 이 반환된 카테고리가 맵의 key로 쓰인다. value는 같은 key를 공유하는 value들의 리스트다.
words.collect(groupingBy(word -> alphaetize(word)));
// alphaetize 한 결과가 같은 단어들의 리스트로 매핑하는 Map을 생성한다.
joining
CharSequence
인스턴스의 스트림에만 적용 가능하다. 매개변수를 사용하지 않으면 단순히 원소들을 concat
하는 것과 같은 결과를 반환한다.
Leave a comment