1 minute read

스트림은 함수형 프로그래밍에 기초한 패러다임이다. 핵심은 계산을 일련의 변환으로 재구성하는 부분이고, 각 변환 단계는 이전 단계의 결과를 받아 처리하는 함수여야 한다.

이 패러다임을 준수하기 위해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