Collector 인터페이스는 collect 함수를 사용할 때 넣어줘야 하는 객체인데요
public interface Collector<T, A, R> {
/**
* A function that creates and returns a new mutable result container.
*
* @return a function which returns a new, mutable result container
*/
Supplier<A> supplier();
/**
* A function that folds a value into a mutable result container.
*
* @return a function which folds a value into a mutable result container
*/
BiConsumer<A, T> accumulator();
/**
* A function that accepts two partial results and merges them. The
* combiner function may fold state from one argument into the other and
* return that, or may return a new result container.
*
* @return a function which combines two partial results into a combined
* result
*/
BinaryOperator<A> combiner();
/**
* Perform the final transformation from the intermediate accumulation type
* {@code A} to the final result type {@code R}.
*
* <p>If the characteristic {@code IDENTITY_FINISH} is
* set, this function may be presumed to be an identity transform with an
* unchecked cast from {@code A} to {@code R}.
*
* @return a function which transforms the intermediate result to the final
* result
*/
Function<A, R> finisher();
/**
* Returns a {@code Set} of {@code Collector.Characteristics} indicating
* the characteristics of this Collector. This set should be immutable.
*
* @return an immutable set of collector characteristics
*/
Set<Characteristics> characteristics();
}
supplier 은 처음 시작을 위해 필요한 자료구조를 가지고 있습니다
accumulator 은 어떻게 데이터들을 합치는지에 대한 것을 다루고 있습니다
combiner 은 병렬 스트림에서 결과를 어떻게 합칠지를 다루고 있습니다
finisher 은 자료구조를 진짜 결과로 반환시켜주는 역할을 합니다
characteristics 는 이 콜렉터가 어떤 특성을 가지고 있는 set을 반환합니다
enum Characteristics {
/**
* Indicates that this collector is <em>concurrent</em>, meaning that
* the result container can support the accumulator function being
* called concurrently with the same result container from multiple
* threads.
*
* <p>If a {@code CONCURRENT} collector is not also {@code UNORDERED},
* then it should only be evaluated concurrently if applied to an
* unordered data source.
*/
CONCURRENT,
/**
* Indicates that the collection operation does not commit to preserving
* the encounter order of input elements. (This might be true if the
* result container has no intrinsic order, such as a {@link Set}.)
*/
UNORDERED,
/**
* Indicates that the finisher function is the identity function and
* can be elided. If set, it must be the case that an unchecked cast
* from A to R will succeed.
*/
IDENTITY_FINISH
}
Characteristics 를 보면 이렇게 3가지 옵션을 줄 수 있습니다
병렬 스트림으로 가면, CONCURRENT + UNORDERED 로 했을 경우 순서 보장이 되지 않는 것을 확인할 수 있었습니다
단일 스트림일 경우 CONCURRENT 가 있다고 해도, 굳이? CONCURRENT 를 체크하지 않는 것을 볼 수 있었고요
public class StringCollector implements Collector<String, StringBuilder, String> {
@Override
public Supplier<StringBuilder> supplier() {
return StringBuilder::new;
}
@Override
public BiConsumer<StringBuilder, String> accumulator() {
return StringBuilder::append;
}
@Override
public BinaryOperator<StringBuilder> combiner() {
return StringBuilder::append;
}
@Override
public Function<StringBuilder, String> finisher() {
return StringBuilder::toString;
}
@Override
public Set<Characteristics> characteristics() {
return Set.of(CONCURRENT);
}
}
실제로 이런 방식으로 구현할 수 있는데요
StringBuilder 를 이용해서 합치는 과정을 직접 구현했습니다
final String result = Stream.of("1", "2", "3", "4").collect(new StringCollector());
System.out.println(result);
이런 식으로 합치면 1234 를 얻을 수 있습니다
final List<String> list = new ArrayList<>();
for (int i = 0; i < 1000000; i++) {
for (int j = 0; j < 10; j++) {
list.add("" + j);
}
}
// System.out.println(list);
final String result = list.stream().collect(new StringCollector());
for (int i = 1; i < result.length(); i++) {
final int j = result.charAt(i) - result.charAt(i - 1);
if (j != 1 && j != -9) {
System.out.println("error");
}
}
System.out.println(result);
테스트 했던 과정은 이렇습니다
'Java' 카테고리의 다른 글
우리 프로젝트에서 java 17을 사용하게 된 이유 (0) | 2023.07.02 |
---|---|
reflection 을 주의해서 사용해야 하는 이유 (2) | 2023.03.26 |
Java 멀티 쓰레드 아는체하기 (1) | 2023.03.05 |
Java Exception 알아보기 (0) | 2023.02.27 |
Java 초기화 되지 않음을 표현하는 방법 (0) | 2023.02.27 |