J'ai appris en étudiant que Parallelism
est un des principaux avantages de Spliterator
.
Cela peut être une question de base, mais quelqu'un peut-il m'expliquer les principales différences entre Iterator
et Spliterator
et donner quelques exemples?
Les noms sont assez explicites pour moi. Spliterator
== Iterator Splittable: il peut diviser une source, et il peut aussi l'itérer. Il a à peu près les mêmes fonctionnalités qu'un Iterator
, mais avec en plus ce qu'il peut potentiellement split en plusieurs morceaux: c'est à cela que sert le trySplit
. Le fractionnement est nécessaire pour le traitement parallèle.
Un Iterator
a toujours une taille inconnue: vous ne pouvez parcourir les éléments que via hasNext/next
; un Spliterator
peut fournir la taille (améliorant ainsi d'autres opérations trop en interne); soit exacte via getExactSizeIfKnown
ou approximative via estimateSize
.
D'un autre côté, tryAdvance
est ce que hasNext/next
provient d'un Iterator
, mais c'est une méthode unique, beaucoup plus facile à raisonner, IMO. Lié à cela, est forEachRemaining
qui dans l'implémentation par défaut délègue à tryAdvance
, mais il ne doit pas toujours être comme ça (voir ArrayList
par exemple).
Un Spliterator est également un Iterator "plus intelligent", via ses propriétés internes comme DISTINCT
ou SORTED
, etc. (que vous devez fournir correctement lors de l'implémentation de votre propre Spliterator
). Ces indicateurs sont utilisés en interne pour désactiver les opérations inutiles; voir par exemple cette optimisation:
someStream().map(x -> y).count();
Parce que la taille ne change pas dans le cas du flux, le map
peut être entièrement ignoré, car tout ce que nous faisons est de compter.
Vous pouvez créer un Spliterator autour d'un Iterator si vous en avez besoin, via:
Spliterators.spliteratorUnknownSize(yourIterator, properties)
Un Iterator
est une simple représentation d'une série d'éléments qui peuvent être itérés.
par exemple:
List<String> list = Arrays.asList("Apple", "Banana", "Orange");
Iterator<String> i = list.iterator();
i.next();
i.forEachRemaining(System.out::println);
#output
Banana
Orange
Un Spliterator
peut être utilisé pour diviser un ensemble d'éléments donné en plusieurs ensembles afin que nous puissions effectuer une sorte d'opérations/calculs sur chaque ensemble dans différents threads indépendamment, en profitant éventuellement du parallélisme. Il est conçu comme un analogue parallèle d'itérateur. Outre les collections, la source des éléments couverts par un séparateur peut être, par exemple, un tableau, un canal IO ou une fonction de générateur).
Il existe 2 méthodes principales dans l'interface Spliterator
.
- tryAdvance () et forEachRemaining ()
Avec tryAdvance (), nous pouvons parcourir les éléments sous-jacents un par un (tout comme Iterator.next ()). Si un élément restant existe, cette méthode effectue l'action consommateur sur lui, en retournant true; sinon renvoie faux.
Pour une traversée en bloc séquentielle, nous pouvons utiliser 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);
Production:
Apple
--- bulk traversal
Banana
Orange
--- attempting tryAdvance again
Element exists: false
- Spliterator trySplit ()
Divise ce séparateur en deux et renvoie le nouveau:
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);
Production:
Banana
Orange
-- traversing the other half of the spliterator ---
Apple
Une méthode trySplit idéale devrait diviser ses éléments exactement en deux, permettant un calcul parallèle équilibré.
Le processus de division est également appelé "partitionnement" ou "décomposition".