web-dev-qa-db-ja.com

Java8でのイテレーターとスプリッターの違い

ParallelismSpliteratorの主な利点であることを研究しているときに知りました。

これは基本的な質問かもしれませんが、IteratorSpliteratorの主な違いを説明して例を挙げてもらえますか?

19
NullPointer

名前は私にはほとんど自明です。 Spliterator == Splittable Iterator:ソースを分割したり、反復したりすることもできます。おおまかにIteratorと同じ機能を持っていますが、潜在的にsplitを複数に分割できる追加の機能があります。これがtrySplitの目的です。並列処理には分割が必要です。

Iteratorのサイズは常に不明です:hasNext/nextを介してのみ要素をトラバースできます。 Spliteratorはサイズを提供できます(したがって、他の操作も内部的に改善します)。 getExactSizeIfKnownによる正確なもの、またはestimateSizeによる概算のいずれか。

一方、tryAdvancehasNext/nextIteratorから得られたものですが、IMOの方がはるかに簡単な単一の方法です。これに関連するのはforEachRemainingで、デフォルトの実装ではtryAdvanceに委譲されますが、常にこのようである必要はありません(たとえば、ArrayListを参照)。

Spliteratorは、DISTINCTSORTEDなどの内部プロパティ(独自のSpliteratorを実装するときに正しく指定する必要がある)を介した「よりスマートな」イテレーターでもあります。これらのフラグは、不要な操作を無効にするために内部的に使用されます。たとえばこの最適化を参照してください:

 someStream().map(x -> y).count();

ストリームの場合はサイズが変化しないため、カウントするだけなので、mapは完全にスキップできます。

必要に応じて、イテレーターの周りにスプリッターを作成できます。

Spliterators.spliteratorUnknownSize(yourIterator, properties)
22
Eugene

Iteratorは、反復できる一連の要素の単純な表現です。

例えば:

 List<String> list = Arrays.asList("Apple", "Banana", "Orange");
 Iterator<String> i = list.iterator();
 i.next();
 i.forEachRemaining(System.out::println);

#output
Banana
Orange

Spliteratorを使用して、特定の要素セットを複数のセットに分割し、並列処理を利用して、異なるスレッドで各セットに対してある種の演算/計算を個別に実行できます。 Iteratorの並列アナログとして設計されています。コレクション以外に、スプリッターでカバーされる要素のソースは、たとえば、配列、IOチャネル、またはジェネレーター関数です。

Spliteratorインターフェースには2つの主要なメソッドがあります。

-tryAdvance()およびforEachRemaining()

TryAdvance()を使用すると、(Iterator.next()のように)基礎となる要素を1つずつトラバースできます。残りの要素が存在する場合、このメソッドはその要素に対してコンシューマーアクションを実行し、trueを返します。それ以外の場合はfalseを返します。

順次バルクトラバーサルの場合、forEachRemaining()を使用できます。

 List<String> list = Arrays.asList("Apple", "Banana", "Orange");
 Spliterator<String> s = list.spliterator();
 s.tryAdvance(System.out::println);
 System.out.println(" --- bulk traversal");
 s.forEachRemaining(System.out::println);

 System.out.println(" --- attempting tryAdvance again");
 boolean b = s.tryAdvance(System.out::println);
 System.out.println("Element exists: "+b);

出力:

Apple
 --- bulk traversal
Banana
Orange
 --- attempting tryAdvance again
Element exists: false

-Spliterator trySplit()

このスプリッターを2つに分割し、新しいスプリッターを返します。

  List<String> list = Arrays.asList("Apple", "Banana", "Orange");

  Spliterator<String> s = list.spliterator();
  Spliterator<String> s1 = s.trySplit();

  s.forEachRemaining(System.out::println);
  System.out.println("-- traversing the other half of the spliterator --- ");
  s1.forEachRemaining(System.out::println);

出力:

Banana
Orange
-- traversing the other half of the spliterator ---
Apple

理想的なtrySplitメソッドは、要素を正確に半分に分割し、バランスの取れた並列計算を可能にする必要があります。

分割プロセスは、「パーティション化」または「分解」とも呼ばれます。

15
Pankaj Singhal