タイプの確定#
カスタムコレクタを実装するには、まずタイプを確定する必要があります。
- 収集する要素のタイプ
- アキュムレータ /accumulate のタイプ
- 最終結果のタイプ
次のようなコレクタを実装すると仮定します。
public class GroupingBy<T,K> implements Collector<T,Map<K,List<T>>,Map<K,List<T>>>
それぞれのタイプは次のとおりです。
- T
- Map<K,List>
- Map<K,List>
コレクタのコンポーネントの実装#
コレクタには 4 つの重要なコンポーネントがあります。これらはすべて関数です。
- supplier
- accumulator
- combiner
- finisher
supplier#
supplier はコンテナを作成するために使用されます。
@Override
public Supplier<Map<K, List<T>>> supplier() {
return ()-> new HashMap<>();
}
accumulator はアキュムレータであり、前の結果に次の内容を追加するために reduce の第 2 引数として使用されます。
@Override
public BiConsumer<Map<K, List<T>>, T> accumulator() {
return (accumulator,ele)->{
K key = this.classifier.apply(ele);
List<T> tList = accumulator.get(key);
if (tList == null){
tList = new ArrayList<>();
}
tList.add(ele);
accumulator.put(key,tList);
};
}
次の要素を追加する前に、マップにリストがあるかどうかを確認します。
重要なポイントは、キーの取得です。渡された classifier によって行われ、classifier を使用してキーを取得します。
combiner#
reduce の第 3 引数に相当し、生成されたコンテナを結合します。
@Override
public BinaryOperator<Map<K, List<T>>> combiner() {
return (l,r)->{
l.putAll(r);
return l;
};
}
後のコンテナを前のコンテナに直接結合して返します。
finisher#
最終結果を記述します。
@Override
public Function<Map<K, List<T>>, Map<K, List<T>>> finisher() {
return accumulator->accumulator;
}
追加の characteristics#
データの返り値の形式を記述します。
@Override
public Set<Characteristics> characteristics() {
return Collections.unmodifiableSet(EnumSet.of(Characteristics.IDENTITY_FINISH));
}
関連説明:
/**
* Characteristics indicating properties of a {@code Collector}, which can
* be used to optimize reduction implementations.
*/
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
}