개발 공부/Java & Spring

24. Collector 구현하기

빵다희 2023. 3. 29. 20:04
Collectors
: collect()가 스트림의 요소를 수집하는데에 대한 방법을 정의한다.
: static으로 제공하는 것을 가져다 사용할 수도 있고, Collector인터페이스를 구현받아서 직접 작성할 수도 있다.

💡Collector인터페이스

public interface Collector<T, A, R> {

   Supplier<A>          supplier();
   BiConsumer<A,T>      accumulator();
   BinaryOperator<A>    combiner();
   Fuction<A, R>        finisher();
   
   Set<Characteristics> characteristics(); // 컬렉터의 특성이 담긴 Set을 반환
   ...
}

✔️ 직접 구현해야하는 것은 위의 5개의 메서드인데, Characteristics()를 제외하면 모두 반환타입이 함수형 인터페이스이다.

-> 4개의 람다식 작성이 필요하다.

함수 내용
supplier() 작업결과를 저장할 공간을 제공
accumulator() 스트림의 요소를 수집할 방법을 제공
combiner() 병렬스트림의 경우, 여러 쓰레드에 의해 처리된 결과를 어떻게 합칠지에 대해 정의
finisher() 결과를 반환할 방법을 제공, 변환이 필요없다면 항등함수인 Function.identity()를 반환.

✔️ characteristics()는 컬렉터가 수행하는 작업의 속성에 대한 정보를 제공하기 위한것이다.

Characteristics.CONCURRENT 병렬로 처리할 수 있는 작업
Characteristics.UNORDERED 스트림의 요소가 순서가 유지될 필요가 없는 작업
Characteristics.IDENTITY_FINISH finisher()가 항등 함수인 직업
/* 설정 예시 */
public Set<Characteristics> Characteristics(){
	return Collections.unmodifiableSet(EnumSet.of(
    	Collector.Characteristics.CONCURRENT,
        Collector.Characteristics.UNORDERED
    ));
}

/* 아무런 속성도 지정하고 싶지 않을 때, */
 Set<Characteristics> Characteristics(){
	return Collections.emptySet();  //비어있는 set반환
    
}

✔️ reduce()와 collect()

- finisher() 제외하고 supplier(), accumulator(), combiner()는 모두 리듀싱에도 있는 개념이다.
결국 Collector도 내부적으로 처리하는 과정이 리듀싱과 같다는 것을 의미한다. 
- reduce()와 collect()는 근본적으로는 하는 일이 같다.
- collect()는 그룹화와 분할, 집계에 더 유용하게 쓰인다.
- 병렬화에 있어서는 reduce()보다 collect()가 더 유리하다.

✔️문자열을 하나로 결합하는 collector 구현예시

import java.util.Arrays;
import java.util.Collections;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class CollectorEx1 {
    public static void main(String[] args) {
        String[] strArr = {"aaa","bbb","ccc"};
        Stream<String> strStream = Stream.of(strArr);

        String result = strStream.collect(new ConcatCollector());

        System.out.println(Arrays.toString(strArr));
        System.out.println("result="+result);
    }
}
class ConcatCollector implements Collector<String, StringBuilder,String>{


    @Override
    public Supplier<StringBuilder> supplier() {
        /* 작업 결과를 저장할 공간을 제공 */
        return ()->new StringBuilder();
//        return StringBuilder::new;
    }

    @Override
    public BiConsumer<StringBuilder, String> accumulator() {
        /* 스트림의 요소를 수집할 방법 */
        return (sb, s) -> sb.append(s);
//        return StringBuilder::append;
    }
    @Override
    public Function<StringBuilder, String> finisher() {
        /* 결과 반환 방식 */
        return sb-> sb.toString();
//        return StringBuilder::toString;
    }
    @Override
    public BinaryOperator<StringBuilder> combiner() {
        /* 병렬 스트림의 경우 저장공간을 병합할 방법 */
        return (sb, sb2) -> sb.append(sb2);
//        return StringBuilder::append;
    }

    @Override
    public Set<Characteristics> characteristics() {
        /* 아무런 속성도 지정하지 않음 */
        return Collections.emptySet();
    }
}

출력결과는 

[aaa, bbb, ccc]
result=aaabbbccc

이고, 주석을 풀고 람다식을 주석처리하여도 실행결과는 같다.

728x90
반응형

'개발 공부 > Java & Spring' 카테고리의 다른 글

26. 표준 입출력과 RandomAccessFile  (0) 2023.04.16
25. 문자기반의 보조스트림  (0) 2023.04.09
23. 스트림 - collect()  (0) 2023.03.26
22. 스트림의 최종연산  (0) 2023.03.26
21. fork & join 프레임워크  (0) 2023.03.09