Comprendre le séparateur, le collecteur et le stream dans Java 8

Je ne parviens pas à comprendre l’interface Stream de Java 8, en particulier en ce qui Spliterator interfaces Spliterator et Collector . Mon problème est que je ne peux tout simplement pas encore comprendre les Spliterator et Collector et, par conséquent, l’interface Stream me semble encore un peu obscure.

Qu’est-ce qu’un Spliterator et un Collector , et comment puis-je les utiliser? Si je suis disposé à écrire mon propre Spliterator ou Collector (et probablement mon propre Stream dans ce processus), que dois-je faire et ne pas faire?

J’ai lu quelques exemples dispersés sur le Web, mais comme tout ici est encore nouveau et sujet à des changements, les exemples et les didacticiels sont encore très rares.

Vous ne devriez presque jamais avoir à traiter avec Spliterator tant qu’utilisateur; cela ne devrait être nécessaire que si vous écrivez vous-même les types de Collection et que vous souhaitez également optimiser les opérations parallèles sur ces types.

Pour ce que cela vaut, un Spliterator est un moyen d’opérer les éléments d’une collection de manière à ce qu’il soit facile de séparer une partie de la collection, par exemple parce que vous êtes en parallélisation et que vous voulez qu’un thread travaille sur une partie de la collection. , un fil pour travailler sur une autre partie, etc.

Vous ne devriez essentiellement jamais enregistrer les valeurs de type Stream dans une variable. Stream est en quelque sorte un Iterator , en ce sens qu’il s’agit d’un object à usage unique que vous utiliserez presque toujours dans une chaîne fluide, comme dans l’exemple Javadoc:

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

Collector est la version la plus généralisée et la plus abstraite possible d’une opération “Reduce” à la carte / Reduce; en particulier, il doit prendre en charge les étapes de parallélisation et de finalisation. Les exemples de Collector incluent:

  • sommation, p.ex. Collectors.reducing(0, (x, y) -> x + y)
  • Ajout de SsortingngBuilder, par exemple Collector.of(SsortingngBuilder::new, SsortingngBuilder::append, SsortingngBuilder::append, SsortingngBuilder::toSsortingng)

Spliterator signifie fondamentalement “Itérateur séparable”.

Un seul thread peut traverser / traiter l’intégralité du Spliterator lui-même, mais le Spliterator a également une méthode trySplit() qui “décompose” une section pour que quelqu’un d’autre (généralement, un autre thread) traite, laissant moins de travail au spliterator actuel.

Collector combine la spécification d’une fonction de reduce (de la renommée de réduction de carte), avec une valeur initiale et une valeur pour combiner deux résultats (permettant ainsi de combiner les résultats de stream de travail divisés).

Par exemple, le collecteur le plus élémentaire aurait une valeur initiale de 0, appendait un entier à un résultat existant et «combinerait» deux résultats en les ajoutant. Somme donc un stream d’entiers divisé.

Voir:

  • Spliterator.trySplit()
  • Collector

Voici des exemples d’utilisation des collecteurs prédéfinis pour effectuer des tâches de réduction mutables courantes:

  // Accumulate names into a List List list = people.stream().map(Person::getName).collect(Collectors.toList()); // Accumulate names into a TreeSet Set set = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new)); // Convert elements to ssortingngs and concatenate them, separated by commas Ssortingng joined = things.stream() .map(Object::toSsortingng) .collect(Collectors.joining(", ")); // Compute sum of salaries of employee int total = employees.stream() .collect(Collectors.summingInt(Employee::getSalary))); // Group employees by department Map> byDept = employees.stream() .collect(Collectors.groupingBy(Employee::getDepartment)); // Compute sum of salaries by department Map totalByDept = employees.stream() .collect(Collectors.groupingBy(Employee::getDepartment, Collectors.summingInt(Employee::getSalary))); // Partition students into passing and failing Map> passingFailing = students.stream() .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD)); 

Interface Spliterator – est une caractéristique essentielle de Streams .

Les méthodes par défaut stream() et parallelStream() sont présentées dans l’interface Collection . Ces méthodes utilisent le spliterator à travers l’appel au spliterator() :

 ... default Stream stream() { return StreamSupport.stream(spliterator(), false); } default Stream parallelStream() { return StreamSupport.stream(spliterator(), true); } ... 

Spliterator est un iterator interne qui divise le stream en parties plus petites. Ces petites pièces peuvent être traitées en parallèle.

Entre autres méthodes, il y a deux plus importantes pour comprendre le spliterator:

  • boolean tryAdvance(Consumer< ? super T> action) Contrairement à l’ Iterator , il tente d’effectuer l’opération avec l’élément suivant. Si l’opération est exécutée avec succès, la méthode renvoie true . Sinon, renvoie false – cela signifie qu’il ya absence d’élément ou de fin du stream.

  • Spliterator trySplit() Cette méthode permet de diviser un dataset en plusieurs ensembles plus petits selon un ou plusieurs critères (taille du fichier, nombre de lignes, etc.).