Comprendre Spliterator, Collector et Stream en Java 8

j'ai du mal à comprendre l'interface Stream en Java 8, en particulier lorsqu'il s'agit des interfaces Spliterator et Collector . Mon problème est que je ne peux tout simplement pas comprendre encore les interfaces Spliterator et Collector , et en conséquence l'interface Stream est encore un peu obscur pour moi.

ce qui est exactement un Spliterator et un Collector , et comment puis-je les utiliser? Si je suis prêt à é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 puisque tout ici est encore nouveau et sujet à des changements, les exemples et les tutoriels sont encore très rares.

129
demandé sur Sam Berry 2013-10-08 02:05:12

4 réponses

vous ne devriez presque certainement jamais avoir à traiter avec Spliterator comme un utilisateur; il ne devrait être nécessaire si vous écrivez Collection types vous-même et également l'intention d'optimiser les opérations parallélisées sur eux.

pour ce que ça vaut, un Spliterator est une façon d'opérer sur les éléments d'une collection d'une manière qu'il est facile de séparer une partie de la collection, par exemple parce que vous êtes parallélisé et que vous voulez un fil pour travailler sur une partie de la collection, un thread à travailler sur une autre partie, etc.

vous ne devriez pas être essentiellement des valeurs de sauvegarde de type Stream à une variable, soit. Stream est un peu comme un Iterator , en ce qu'il s'agit d'un objet à usage unique que vous utiliserez presque toujours dans une chaîne fluide, comme dans L'exemple de Javadoc:

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

Collector est la plus généralisée, abstrait version possible de "réduire" l'opération de la map / reduce; en particulier, il doit soutenir les étapes de parallélisation et de finalisation. Exemples de Collector s comprennent:

  • sommation, p.ex. Collectors.reducing(0, (x, y) -> x + y)
  • StringBuilder ajoutant, par exemple, Collector.of(StringBuilder::new, StringBuilder::append, StringBuilder::append, StringBuilder::toString)
132
répondu Louis Wasserman 2016-11-23 19:13:02

Spliterator signifie fondamentalement " itérateur séparable".

fil simple peut traverser / traiter le Spliterator entier lui-même, mais le Spliterator a également une méthode trySplit() qui va "séparer" une section pour quelqu'un d'autre (généralement, un autre fil) à traiter -- laissant le spliterator actuel avec moins de travail.

Collector combine la spécification d'une fonction reduce (de map-reduce fame), avec une valeur initiale, et une valeur permettant de combiner deux résultats (permettant ainsi de combiner les résultats de flux de travail fractionnés).)

par exemple, le collecteur le plus basique aurait une valeur initiale de 0, ajouterait un entier sur un résultat existant, et "combinerait" deux résultats en les ajoutant. Ainsi sommant un jet splitterated des entiers.

voir:

83
répondu Thomas W 2014-03-28 17:26:57

voici des exemples d'utilisation de collecteurs prédéfinis pour effectuer des tâches communes de réduction mutable:

 // Accumulate names into a List
 List<String> list = people.stream().map(Person::getName).collect(Collectors.toList());

 // Accumulate names into a TreeSet
 Set<String> set = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));

 // Convert elements to strings and concatenate them, separated by commas
 String joined = things.stream()
                       .map(Object::toString)
                       .collect(Collectors.joining(", "));

 // Compute sum of salaries of employee
 int total = employees.stream()
                      .collect(Collectors.summingInt(Employee::getSalary)));

 // Group employees by department
 Map<Department, List<Employee>> byDept
     = employees.stream()
                .collect(Collectors.groupingBy(Employee::getDepartment));

 // Compute sum of salaries by department
 Map<Department, Integer> totalByDept
     = employees.stream()
                .collect(Collectors.groupingBy(Employee::getDepartment,
                                               Collectors.summingInt(Employee::getSalary)));

 // Partition students into passing and failing
 Map<Boolean, List<Student>> passingFailing =
     students.stream()
             .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD));
5
répondu Ajay 2017-05-24 04:01:04

Interface Spliterator - est une caractéristique principale de Streams .

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

...

default Stream<E> stream() {
    return StreamSupport.stream(spliterator(), false);
}

default Stream<E> parallelStream() {
    return StreamSupport.stream(spliterator(), true);
}

...

Spliterator est un itérateur interne qui brise le flux dans les plus petites pièces. Ces petites pièces peuvent être traitées en parallèle.

parmi les autres méthodes, il y a deux plus importantes pour comprendre le Spliterator:

  • boolean tryAdvance(Consumer<? super T> action) Contrairement à la Iterator , il essaie 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 . Autrement, renvoie false - cela signifie qu'il y a absence d'élément ou d'extrémité du flux.

  • Spliterator<T> trySplit() Cette méthode permet de diviser un ensemble de données en plusieurs ensembles plus petits selon l'un ou l'autre des critères (Taille du fichier, nombre de lignes, etc.).

1
répondu Aleksey Bykov 2018-07-31 09:02:01