-
Stream(스트림) - 7. Collector 구현 (최종연산 3/3)Java 2020. 3. 11. 22:14반응형
Collector 작성
Collector인터페이스를 구현
Collector Interface
직접 구현해야 하는 5개의 메서드
public interface Collector<T, A, R> { Supplier<A> supplier(); BiConsumer<A, T> accumulator(); BinaryOperator<A> combiner(); Function<A, R> finisher(); Set<Characteristics> characteristics(); // 컬렉터의 특성이 담긴 Set 반환 ... }
characteristics()를 제외하면 모두 반환타입이 함수형 인터페이스 = 4개의 람다식
supplier() 작업 결과를 저장할 공간 제공 accumulator() 스트림의 요소를 수집(collect)할 방법 제공 스트림 요소를 어떻게 supplier가 제공한 공간에 누적할지 정의 combineder() 두 저장공간을 병합할 방법을 제공(병렬 스트림) 병렬 스트림인 경우, 여러 쓰레드에 의해 처리된 결과를 어떻게 합칠지 정의 finisher() 결과를 최종적으로 변환할 방법을 제공 변환이 필요없다면 항등 함수인 Function.identity()를 반환하면 됨 public Function finisher() { return Function.identity(); // 항등 함수 반환. return x -> x;와 동일 }
characteristics()는 컬렉터가 수행하는 작업의 속성에 대한 정보를 제공하기 위한 것
아래 세가지 속성 중 해당하는 것을 Set에 담아서 반환하도록 구현하면 됨
Characteristics.CONCURRENT 병렬로 처리할 수 있는 작업 Characteristics.UNORDERED 스트림의 요소의 순서가 유지될 필요가 없는 작업 Characteristics.IDENTITY_FINISH finisher()가 항등 함수인 작업
public Set<Characteristics> charateristics() { return Collections.unmodifiableSet(EnumSet.of( Collector.Characteristics.CONCURRENT, Collector.Characteristics.UNORDERED )); }
아무런 속성도 지정하고 싶지 않은 경우
Set<Characteristics> characteristics() { return Collections.emptySet(); // 지정할 특성이 없는 경우 비어있는 Set 반환 }
reduce() VS collect()
finisher()를 제외한 supplier(), accumulator(), combiner()는 리듀싱에서 배울 때 등장한 개념
- Collector도 내부적으로 처리하는 과정이 리듀싱과 같다는 의미
IntStream의 count(), sum(), max(), min() 등이 reduce()로 구현되어 있었음
- collect()로도 count()등의 메서드로 같은 일을 할 수 있음
long count = studentStream.count(); long count = studentStream.collect(Collectors.counting());
근본적으로 하는 일이 같음
collect() : 그룹화와 분할, 집계 등에 유용하게 쓰이고 병렬화에 있어서 reduce()보다 collect()가 더 유리함
reduce()에 대해 잘 이해한다면, Collector를 구현하는 것이 어렵지 않음
예제 - Stream<String>의 모든 문자열을 하나로 결합해서 String으로 반환하는 컬렉터
String 배열의 모든 문자열을 하나의 문자열로 합치려면?
String[] strArr = { "aaa", "bbb", "ccc" }; StringBuffer sb = new StringBuffer(); // supplier(), 저장할 공간 생성 for(String tmp : strArr) { sb.append(tmp); // accumulator(), sb에 요소를 저장 } String result = sb.toString(); // finisher(), StringBuffer를 String으로 변환
Stream<String>의 모든 문자열을 하나로 결합해서 String으로 반환하는 ConcatCollector
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; public class ConcatCollector implements Collector<String, StringBuilder, String> { @Override public Supplier<StringBuilder> supplier() { return StringBuilder::new; // return () -> new StringBuilder(); } @Override public BiConsumer<StringBuilder, String> accumulator() { return StringBuilder::append; // return (sb, s) -> sb.append(s); } @Override public BinaryOperator<StringBuilder> combiner() { return StringBuilder::append; // return (sb, sb2) -> sb.append(sb2); } @Override public Function<StringBuilder, String> finisher() { return StringBuilder::toString; // return sb -> sb.toString(); } @Override public Set<Characteristics> characteristics() { return Collections.emptySet(); } }
만든 Collector를 사용하는 클래스
import java.util.Arrays; import java.util.stream.Stream; public class CollectorUse { public static void main(String[] args) { String[] strings = { "Jamie", "JAMIE", "jamie" }; Stream<String> stringStream = Stream.of(strings); String result = stringStream.collect(new ConcatCollector()); System.out.println(Arrays.toString(strings)); System.out.println("result = " + result); } } [Jamie, JAMIE, jamie] result = JamieJAMIEjamie
반응형'Java' 카테고리의 다른 글
자바의 I/O (0) 2020.03.13 Stream(스트림) - 8. 스트림의 변환 (0) 2020.03.11 Stream(스트림) - 6. collect() (최종연산 2/3) (0) 2020.03.11 Stream(스트림) - 5. 최종 연산 1/3 (0) 2020.03.10 Stream(스트림) - 4. Optional<T> & OptionalInt (0) 2020.03.10