Java 8でのSpliterator、Collector、Streamについて


143

StreamJava 8 のインターフェースを理解するのに問題がSpliteratorありCollectorます。特に、とインターフェースに関係しているところです。私の問題はSpliteratorCollectorインターフェイスとインターフェイスをまだ理解できないことStreamです。その結果、インターフェイスはまだ少しあいまいです。

正確にはa Spliteratorとa は何Collectorですか?どのように使用できますか?私が自分で(SpliteratorまたはCollectorおそらくStreamそのプロセスで自分自身を)書こうと思っている場合、私は何をすべきで、何をすべきではありませんか?

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

回答:


142

ほとんどSpliteratorの場合、ユーザーとして対処する必要はありません。それはあなたしている書き込み場合に必要であるべきCollection種類の自分自身とそれらに並列化された運用を最適化しようとします。

価値があるのSpliteratorは、a がコレクションの一部を簡単に分割できるようにコレクションの要素を操作する方法です。たとえば、並列化していて、1つのスレッドでコレクションの一部を処理したい場合などです。 1つのスレッドで別のパーツなどを処理する

本質的に、型の値をStream変数に保存してはいけません。 StreamソートのようなのであるIterator、それはあなたがほとんど常にJavadocの例のように、流暢なチェーンで使用しますことを一回使用のオブジェクトのことで、:

int sum = widgets.stream()
                  .filter(w -> w.getColor() == RED)
                  .mapToInt(w -> w.getWeight())
                  .sum();

Collectormap / reduceによる「reduce」操作の最も一般化された抽象的な可能なバージョンです。特に、並列化とファイナライズのステップをサポートする必要があります。の例は次Collectorのとおりです。

  • 合計、例えば Collectors.reducing(0, (x, y) -> x + y)
  • 追加するStringBuilder Collector.of(StringBuilder::new, StringBuilder::append, StringBuilder::append, StringBuilder::toString)

31
Spliteratorは、コレクションではないIterableをストリーミングする方法も提供します
ボヘミアン

2
私は「マップ/リデュースで用語が意味されるという意味で、リデュース操作」を意味しました
Louis Wasserman

1
Collectors.of削除されたベータ版の古い方法やAM-Iは、何かが足りませんか?完全に(x,y) -> x+yするために、と書くことができますInteger::sum
ジャン=フランソワ・Savard

3
えっと、いや、ごめんなさい、Collectors.ofではなくCollector.ofです。
Louis Wasserman

2
コレクターの例は、各コレクターが何をするかを説明する場合に、より役立ちます。
MiguelMunoz 2017

90

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

シングルスレッドはスプリッター自体全体をトラバース/処理できますが、スプリッターには、trySplit()他の誰か(通常は別のスレッド)が処理するセクションを「分割」して、現在のスプリッターをより少ない作業で残すメソッドもあります。

Collectorreduce(map-reduce名声の)関数の指定を初期値と組み合わせ、2つの結果を組み合わせる関数を組み合わせます(これにより、Spliterated Workストリームの結果を組み合わせることができます)。

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

見る:


2つの結果を組み合わせる値?
Jason Law

@JasonLaw-明確化!提案をありがとう。
トーマスW

5

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

 // 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));

2
これはオペレーションの質問には答えません。さらに、投稿の説明や説明はありません。
2017

4

インターフェイス-StreamsのSpliteratorコア機能です。

stream()そしてparallelStream()、デフォルトの方法は、中に提示されているCollectionインタフェース。これらのメソッドは、への呼び出しを通じてSpliteratorを使用しますspliterator()

...

default Stream<E> stream() {
    return StreamSupport.stream(spliterator(), false);
}

default Stream<E> parallelStream() {
    return StreamSupport.stream(spliterator(), true);
}

...

Spliteratorは、ストリームを小さな部分に分割する内部イテレーターです。これらの小さなパーツは並行して処理できます。

他の方法の中でも、スプリッターを理解するために最も重要な2つがあります。

  • boolean tryAdvance(Consumer<? super T> action) とは異なり、Iterator次の要素で操作を実行しようとします。操作が正常に実行された場合、メソッドはを返しますtrue。それ以外の場合は、戻り値false-要素がないか、ストリームの終わりがあることを意味します。

  • Spliterator<T> trySplit() この方法では、1つまたは別の基準(ファイルサイズ、行数など)に従って、データのセットを多数の小さなセットに分割できます。


「操作が正常に実行された場合。」おそらくこれを言い換える必要があります。tryAdvance javadocがより明確になりました: ´残りの要素が存在する場合、その要素に対して指定されたアクションを実行し、trueを返します。他のリターンはfalse.'
Piroさんが復活モニカ言う
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.