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.
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)
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:
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));
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 à laIterator
, 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 renvoietrue
. Autrement, renvoiefalse
- 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.).