web-dev-qa-db-ja.com

Java 8のスプリッター、コレクター、およびストリームについて

Java 8の Stream インターフェースの理解に問題があります。特に Spliterator および Collector に関係する場合インターフェース。私の問題は、SpliteratorおよびCollectorインターフェースがまだ理解できず、その結果、Streamインターフェースがまだわかりにくいことです。

SpliteratorCollectorとは正確には何ですか?どうすれば使用できますか?独自のSpliteratorまたはCollector(およびおそらくそのプロセスでの独自のStream)を作成する場合は、どうすればよいですか?

ウェブ上に散らばっているいくつかの例を読んでいますが、ここにあるものはすべて新しいものであり、変更される可能性があるため、例とチュートリアルはまだ非常にまばらです。

134
Victor Stafusa

ユーザーとして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に類似した「縮小」操作の最も一般化された抽象可能なバージョンです。特に、並列化とファイナライズのステップをサポートする必要があります。 Collectorsの例は次のとおりです。

  • 加算、例えばCollectors.reducing(0, (x, y) -> x + y)
  • StringBuilderの追加、例えばCollector.of(StringBuilder::new, StringBuilder::append, StringBuilder::append, StringBuilder::toString)
136
Louis Wasserman

Spliteratorは基本的に「分割可能なイテレータ」を意味します。

単一のスレッドはSpliterator自体全体をトラバース/処理できますが、SpliteratorにはメソッドtrySplit()もあります。このメソッドは、他の誰か(通常は別のスレッド)が処理するセクションを「分割」します。

Collectorは、(map-reduce名声の)reduce関数の仕様を初期値と2つの結果を結合する値と組み合わせます(したがって、作業の分割ストリームからの結果を結合できます)。 )

たとえば、最も基本的なコレクターの初期値は0で、既存の結果に整数を追加し、2つの結果を追加して「結合」します。したがって、整数の分割ストリームを合計します。

見る:

86
Thomas W

以下は、事前定義されたコレクターを使用して、一般的な可変削減タスクを実行する例です。

 // 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));
6
Ajay Kumar

インターフェイス 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つまたは別の基準(ファイルサイズ、行数など)に従って、データセットをより小さなセットに分割できます。

2
Aleksey Bykov