Java 8の Stream
インターフェースの理解に問題があります。特に Spliterator
および Collector
に関係する場合インターフェース。私の問題は、Spliterator
およびCollector
インターフェースがまだ理解できず、その結果、Stream
インターフェースがまだわかりにくいことです。
Spliterator
とCollector
とは正確には何ですか?どうすれば使用できますか?独自のSpliterator
またはCollector
(およびおそらくそのプロセスでの独自のStream
)を作成する場合は、どうすればよいですか?
ウェブ上に散らばっているいくつかの例を読んでいますが、ここにあるものはすべて新しいものであり、変更される可能性があるため、例とチュートリアルはまだ非常にまばらです。
ユーザーとしてSpliterator
を扱う必要はほとんどありません。自分でCollection
型を書いており、()でそれらの型の並列化された操作を最適化する場合にのみ必要です。
価値があるものとして、Spliterator
は、コレクションの一部を簡単に分割できるように、コレクションの要素を操作する方法です。並列化していて、1つのスレッドをコレクションの一部で動作させたい、1つのスレッドを別の部分で動作させたい、などです。
基本的に、タイプStream
の値を変数に保存しないでください。 Stream
は、Iterator
のようなものです。Javadocの例のように、ほとんど常に流fluentなチェーンで使用する1回限りの使用オブジェクトです。
int sum = widgets.stream()
.filter(w -> w.getColor() == RED)
.mapToInt(w -> w.getWeight())
.sum();
Collector
は、map/reduceに類似した「縮小」操作の最も一般化された抽象可能なバージョンです。特に、並列化とファイナライズのステップをサポートする必要があります。 Collector
sの例は次のとおりです。
Collectors.reducing(0, (x, y) -> x + y)
Collector.of(StringBuilder::new, StringBuilder::append, StringBuilder::append, StringBuilder::toString)
Spliterator
は基本的に「分割可能なイテレータ」を意味します。
単一のスレッドはSpliterator自体全体をトラバース/処理できますが、SpliteratorにはメソッドtrySplit()
もあります。このメソッドは、他の誰か(通常は別のスレッド)が処理するセクションを「分割」します。
Collector
は、(map-reduce名声の)reduce
関数の仕様を初期値と2つの結果を結合する値と組み合わせます(したがって、作業の分割ストリームからの結果を結合できます)。 )
たとえば、最も基本的なコレクターの初期値は0で、既存の結果に整数を追加し、2つの結果を追加して「結合」します。したがって、整数の分割ストリームを合計します。
見る:
以下は、事前定義されたコレクターを使用して、一般的な可変削減タスクを実行する例です。
// Accumulate names into a List
List<String> list = people.stream().map(Person::getName).collect(Collectors.toList());
// Accumulate names into a TreeSet
Set<String> set = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));
// Convert elements to strings and concatenate them, separated by commas
String joined = things.stream()
.map(Object::toString)
.collect(Collectors.joining(", "));
// Compute sum of salaries of employee
int total = employees.stream()
.collect(Collectors.summingInt(Employee::getSalary)));
// Group employees by department
Map<Department, List<Employee>> byDept
= employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment));
// Compute sum of salaries by department
Map<Department, Integer> totalByDept
= employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment,
Collectors.summingInt(Employee::getSalary)));
// Partition students into passing and failing
Map<Boolean, List<Student>> passingFailing =
students.stream()
.collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD));
インターフェイス Spliterator
-は、 Streams のコア機能です。
stream()
および parallelStream()
デフォルトのメソッドは、 Collection
インターフェースに表示されます。これらのメソッドは、spliterator()
の呼び出しを通じてSpliteratorを使用します。
...
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
default Stream<E> parallelStream() {
return StreamSupport.stream(spliterator(), true);
}
...
Spliteratorは、ストリームを小さな部分に分割する内部反復子です。これらの小さな部品は並行して処理できます。
他の方法の中でも、Spliteratorを理解するために最も重要なものが2つあります。
boolean tryAdvance(Consumer<? super T> action)
Iterator
とは異なり、次の要素で操作を実行しようとします。操作が正常に実行された場合、メソッドはtrue
を返します。それ以外の場合は、false
を返します。これは、要素がないか、ストリームの終わりがあることを意味します。
Spliterator<T> trySplit()
この方法では、1つまたは別の基準(ファイルサイズ、行数など)に従って、データセットをより小さなセットに分割できます。