web-dev-qa-db-fra.com

Différence entre Iterator et Spliterator en Java8

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?

19
NullPointer

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)
22
Eugene

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".

15
Pankaj Singhal