Parallelism
がSpliterator
の主な利点であることを研究しているときに知りました。
これは基本的な質問かもしれませんが、Iterator
とSpliterator
の主な違いを説明して例を挙げてもらえますか?
名前は私にはほとんど自明です。 Spliterator
== Splittable Iterator:ソースを分割したり、反復したりすることもできます。おおまかにIterator
と同じ機能を持っていますが、潜在的にsplitを複数に分割できる追加の機能があります。これがtrySplit
の目的です。並列処理には分割が必要です。
Iterator
のサイズは常に不明です:hasNext/next
を介してのみ要素をトラバースできます。 Spliterator
はサイズを提供できます(したがって、他の操作も内部的に改善します)。 getExactSizeIfKnown
による正確なもの、またはestimateSize
による概算のいずれか。
一方、tryAdvance
はhasNext/next
がIterator
から得られたものですが、IMOの方がはるかに簡単な単一の方法です。これに関連するのはforEachRemaining
で、デフォルトの実装ではtryAdvance
に委譲されますが、常にこのようである必要はありません(たとえば、ArrayList
を参照)。
Spliteratorは、DISTINCT
やSORTED
などの内部プロパティ(独自のSpliterator
を実装するときに正しく指定する必要がある)を介した「よりスマートな」イテレーターでもあります。これらのフラグは、不要な操作を無効にするために内部的に使用されます。たとえばこの最適化を参照してください:
someStream().map(x -> y).count();
ストリームの場合はサイズが変化しないため、カウントするだけなので、map
は完全にスキップできます。
必要に応じて、イテレーターの周りにスプリッターを作成できます。
Spliterators.spliteratorUnknownSize(yourIterator, properties)
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メソッドは、要素を正確に半分に分割し、バランスの取れた並列計算を可能にする必要があります。
分割プロセスは、「パーティション化」または「分解」とも呼ばれます。