J'ai de la difficulté à comprendre l'interface Stream
dans Java 8, en particulier lorsqu'il s'agit de l'interface Spliterator
et Collector
interfaces. Mon problème est que je ne comprends tout simplement pas encore les interfaces Spliterator
et Collector
, de sorte que l'interface Stream
est encore quelque peu obscure pour moi.
En quoi consistent exactement Spliterator
et 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 éparpillés sur le Web, mais comme tout est nouveau et sujet à modifications, les exemples et les didacticiels sont encore très rares.
Vous ne devriez presque certainement jamais avoir à traiter Spliterator
en tant qu'utilisateur; cela ne devrait être nécessaire que si vous écrivez Collection
tapez vous-même et aussi l'intention d'optimiser les opérations parallélisées sur ceux-ci.
Pour ce qui en vaut la peine, une Spliterator
est un moyen de manipuler les éléments d'une collection de manière à pouvoir en séparer une partie, par exemple. parce que vous parallélisez et que vous voulez qu'un thread fonctionne sur une partie de la collection, un thread sur une autre, etc.
En principe, vous ne devriez jamais non plus enregistrer de valeurs de type Stream
dans une variable. Stream
est un peu comme un Iterator
, en ce sens qu'il s'agit d'un objet à usage unique que vous utiliserez presque toujours dans une chaîne courante, comme dans l'exemple Javadoc:
int sum = widgets.stream()
.filter(w -> w.getColor() == RED)
.mapToInt(w -> w.getWeight())
.sum();
Collector
est la version abstraite la plus généralisée possible d'une opération "réduire" à la carte/réduire; en particulier, il doit prendre en charge les étapes de parallélisation et de finalisation. Exemples de Collector
s comprennent:
Collectors.reducing(0, (x, y) -> x + y)
Collector.of(StringBuilder::new, StringBuilder::append, StringBuilder::append, StringBuilder::toString)
Spliterator
signifie fondamentalement "Itérateur divisible".
Un seul thread peut traverser/traiter l'intégralité du Spliterator lui-même, mais celui-ci a également une méthode trySplit()
qui "divise" une section à traiter par quelqu'un d'autre (généralement un autre thread), laissant ainsi moins de travail au spliter actuel.
Collector
combine la spécification d'une fonction reduce
(de la réputation de carte-réduction) avec une valeur initiale et une valeur permettant de combiner deux résultats (ce qui permet de combiner les résultats de flux de travail Spliterated). )
Par exemple, le collecteur le plus élémentaire aurait une valeur initiale égale à 0, ajouterait un entier à un résultat existant et "combinerait" deux résultats en les ajoutant. En sommant ainsi un flux fractionné d’entiers.
Voir:
Voici des exemples d'utilisation des collecteurs prédéfinis pour effectuer des tâches de réduction mutables communes:
// 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 fonctionnalité essentielle de Streams .
Les méthodes stream()
et parallelStream()
== sont présentées dans l'interface Collection
. Ces méthodes utilisent le Spliterator via l'appel à la 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 décompose le flux en parties plus petites. Ces petites pièces peuvent être traitées en parallèle.
Parmi les autres méthodes, il y a deux plus importantes à comprendre le Spliterator:
boolean tryAdvance(Consumer<? super T> action)
Contrairement à 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 retourne true
. Sinon, retourne false
- cela signifie qu'il y a absence d'élément ou de fin du flux.
Spliterator<T> trySplit()
Cette méthode permet de fractionner un ensemble de données en un ensemble beaucoup plus petit en fonction d’un critère ou d’un autre (taille du fichier, nombre de lignes, etc.).