1. Liste des méthodes de la Stream
classe
La Stream
classe a été créée pour faciliter la construction de chaînes de flux de données. Pour ce faire, la Stream<T>
classe a des méthodes qui renvoient de nouveaux Stream
objets.
Chacun de ces flux de données effectue une action simple, mais si vous les combinez en chaînes et ajoutez des fonctions lambda intéressantes , vous disposez d'un mécanisme puissant pour générer la sortie souhaitée. Bientôt, vous verrez par vous-même.
Voici les méthodes de la Stream
classe (uniquement les plus basiques):
Méthodes | Description |
---|---|
|
Crée un flux à partir d'un ensemble d'objets |
|
Génère un flux selon la règle spécifiée |
|
Concatène deux flux |
|
Filtre les données, en ne transmettant que les données qui correspondent à la règle spécifiée |
|
Supprime les doublons. Ne transmet pas les données déjà rencontrées |
|
Trie les données |
|
Effectue une action sur chaque élément du flux |
|
Renvoie un flux qui est tronqué de sorte qu'il ne dépasse pas la limite spécifiée |
|
Ignore les n premiers éléments |
|
Convertit les données d'un type à un autre |
|
Convertit les données d'un type à un autre |
|
Vérifie s'il y a au moins un élément dans le flux qui correspond à la règle spécifiée |
|
Vérifie si tous les éléments du flux correspondent à la règle spécifiée |
|
Vérifie si aucun des éléments du flux ne correspond à la règle spécifiée |
|
Renvoie le premier élément trouvé qui correspond à la règle |
|
Renvoie tout élément du flux qui correspond à la règle |
|
Recherche l'élément minimum dans le flux de données |
|
Renvoie l'élément maximum dans le flux de données |
|
Renvoie le nombre d'éléments dans le flux de données |
|
Lit toutes les données du flux et les renvoie sous forme de collection |
2. Opérations intermédiaires et terminales par la Stream
classe
Comme vous pouvez le voir, toutes les méthodes du tableau ci-dessus ne renvoient pas un Stream
. Ceci est lié au fait que les méthodes de la Stream
classe peuvent être divisées en méthodes intermédiaires (également appelées non-terminales ) et en méthodes terminales .
Méthodes intermédiaires
Les méthodes intermédiaires renvoient un objet qui implémente l' Stream
interface, et elles peuvent être chaînées.
Méthodes terminales
Les méthodes terminales renvoient une valeur autre que a Stream
.
Pipeline d'appel de méthode
Ainsi, vous pouvez créer un pipeline de flux composé de n'importe quel nombre de méthodes intermédiaires et d'un seul appel de méthode de terminal à la fin. Cette approche vous permet d'implémenter une logique plutôt complexe, tout en augmentant la lisibilité du code.

Les données à l'intérieur d'un flux de données ne changent pas du tout. Une chaîne de méthodes intermédiaires est une manière astucieuse (déclarative) de spécifier un pipeline de traitement de données qui sera exécuté après l'appel de la méthode terminale.
En d'autres termes, si la méthode de terminal n'est pas appelée, les données du flux de données ne sont en aucun cas traitées. Ce n'est qu'après l'appel de la méthode de terminal que les données commencent à être traitées conformément aux règles spécifiées dans le pipeline de flux.
stream()
.intemediateOperation1()
.intemediateOperation2()
...
.intemediateOperationN()
.terminalOperation();
Comparaison des méthodes intermédiaires et terminales :
intermédiaire | Terminal | |
---|---|---|
Type de retour | Stream |
pas unStream |
Peut être combiné avec plusieurs méthodes du même type pour former un pipeline | Oui | Non |
Nombre de méthodes dans un seul pipeline | n'importe quel | pas plus d'un |
Produit le résultat final | Non | Oui |
Démarre le traitement des données dans le flux | Non | Oui |
Prenons un exemple.
Supposons que nous ayons un club pour les amoureux des animaux. Demain, le club célèbre le Ginger Cat Day. Le club a des propriétaires d'animaux de compagnie, chacun ayant une liste d'animaux de compagnie. Ils ne se limitent pas aux chats.
Tâche : vous devez identifier tous les noms de tous les chats roux afin de leur créer des cartes de vœux personnalisées pour les " vacances professionnelles " de demain. Les cartes de vœux doivent être triées par âge du chat, du plus vieux au plus jeune.
Tout d'abord, nous fournissons quelques classes pour vous aider à résoudre cette tâche :
public enum Color {
WHITE,
BLACK,
DARK_GREY,
LIGHT_GREY,
FOXY,
GREEN,
YELLOW,
BLUE,
MAGENTA
}
public abstract class Animal {
private String name;
private Color color;
private int age;
public Animal(String name, Color color, int age) {
this.name = name;
this.color = color;
this.age = age;
}
public String getName() {
return name;
}
public Color getColor() {
return color;
}
public int getAge() {
return age;
}
}
public class Cat extends Animal {
public Cat(String name, Color color, int age) {
super(name, color, age);
}
}
public class Dog extends Animal {
public Dog(String name, Color color, int age) {
super(name, color, age);
}
}
public class Parrot extends Animal {
public Parrot(String name, Color color, int age) {
super(name, color, age);
}
}
public class Pig extends Animal {
public Pig(String name, Color color, int age) {
super(name, color, age);
}
}
public class Snake extends Animal {
public Snake(String name, Color color, int age) {
super(name, color, age);
}
}
public class Owner {
private String name;
private List<Animal> pets = new ArrayList<>();
public Owner(String name) {
this.name = name;
}
public List<Animal> getPets() {
return pets;
}
}
Regardons maintenant la Selector
classe, où la sélection sera faite selon les critères spécifiés :
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Selector {
private static List<Owner> owners;
private static void initData() {
final Owner owner1 = new Owner("Ronan Turner");
owner1.getPets().addAll(List.of(
new Cat("Baron", Color.BLACK, 3),
new Cat("Sultan", Color.DARK_GREY, 4),
new Dog("Elsa", Color.WHITE, 0)
));
final Owner owner2 = new Owner("Scarlet Murray");
owner2.getPets().addAll(List.of(
new Cat("Ginger", Color.FOXY, 7),
new Cat("Oscar", Color.FOXY, 5),
new Parrot("Admiral", Color.BLUE, 3)
));
final Owner owner3 = new Owner("Felicity Mason");
owner3.getPets().addAll(List.of(
new Dog("Arnold", Color.FOXY, 3),
new Pig("Vacuum Cleaner", Color.LIGHT_GREY, 8)
));
final Owner owner4 = new Owner("Mitchell Stone");
owner4.getPets().addAll(List.of(
new Snake("Mr. Boa", Color.DARK_GREY, 2)
));
final Owner owner5 = new Owner("Jonathan Snyder");
owner5.getPets().addAll(List.of(
new Cat("Fisher", Color.BLACK, 16),
new Cat("Zorro", Color.FOXY, 14),
new Cat("Margo", Color.WHITE, 3),
new Cat("Brawler", Color.DARK_GREY, 1)
));
owners = List.of(owner1, owner2, owner3, owner4, owner5);
}
}
Il ne reste plus qu'à ajouter du code à la main
méthode. Actuellement, nous appelons d'abord la initData()
méthode, qui remplit la liste des propriétaires d'animaux du club. Ensuite, nous sélectionnons les noms des chats roux triés par leur âge par ordre décroissant.
Examinons d'abord le code qui n'utilise pas de flux pour résoudre cette tâche :
public static void main(String[] args) {
initData();
List<String> findNames = new ArrayList<>();
List<Cat> findCats = new ArrayList<>();
for (Owner owner : owners) {
for (Animal pet : owner.getPets()) {
if (Cat.class.equals(pet.getClass()) && Color.FOXY == pet.getColor()) {
findCats.add((Cat) pet);
}
}
}
Collections.sort(findCats, new Comparator<Cat>() {
public int compare(Cat o1, Cat o2) {
return o2.getAge() - o1.getAge();
}
});
for (Cat cat : findCats) {
findNames.add(cat.getName());
}
findNames.forEach(System.out::println);
}
Voyons maintenant une alternative :
public static void main(String[] args) {
initData();
final List<String> findNames = owners.stream()
.flatMap(owner -> owner.getPets().stream())
.filter(pet -> Cat.class.equals(pet.getClass()))
.filter(cat -> Color.FOXY == cat.getColor())
.sorted((o1, o2) -> o2.getAge() - o1.getAge())
.map(Animal::getName)
.collect(Collectors.toList());
findNames.forEach(System.out::println);
}
Comme vous pouvez le voir, le code est beaucoup plus compact. De plus, chaque ligne du pipeline de flux est une action unique, elles peuvent donc être lues comme des phrases en anglais :
|
Passer d'un Stream<Owner> à unStream<Pet> |
|
Conserver uniquement les chats dans le flux de données |
|
Ne conserver que les chats roux dans le flux de données |
|
Trier par âge dans l'ordre décroissant |
|
Obtenez les noms |
|
Mettre le résultat dans une liste |
3. Création de flux
La Stream
classe a trois méthodes que nous n'avons pas encore couvertes. Le but de ces trois méthodes est de créer de nouveaux threads.
Stream<T>.of(T obj)
méthode
La of()
méthode crée un flux composé d'un seul élément. Ceci est généralement nécessaire lorsque, par exemple, une fonction prend un Stream<T>
objet comme argument, mais que vous n'avez qu'un T
objet. Ensuite, vous pouvez facilement et simplement utiliser la of()
méthode pour obtenir un flux composé d'un seul élément .
Exemple:
Stream<Integer> stream = Stream.of(1);
Stream<T> Stream.of(T obj1, T obj2, T obj3, ...)
méthode
La of()
méthode crée un flux composé d' éléments passés . N'importe quel nombre d'éléments est autorisé. Exemple:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
Stream<T> Stream.generate(Supplier<T> obj)
méthode
La generate()
méthode vous permet de définir une règle qui sera utilisée pour générer l'élément suivant du flux lorsqu'il est demandé. Par exemple, vous pouvez donner un nombre aléatoire à chaque fois.
Exemple:
Stream<Double> s = Stream.generate(Math::random);
Stream<T> Stream.concat(Stream<T> a, Stream<T> b)
méthode
La concat()
méthode concatène les deux flux passés en un seul . Lorsque les données sont lues, elles sont d'abord lues à partir du premier flux, puis à partir du second. Exemple:
Stream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5);
Stream<Integer> stream2 = Stream.of(10, 11, 12, 13, 14);
Stream<Integer> result = Stream.concat(stream1, stream2);
4. Filtrage des données
6 autres méthodes créent de nouveaux flux de données, vous permettant de combiner des flux en chaînes (ou pipelines) de complexité variable.
Stream<T> filter(Predicate<T>)
méthode
Cette méthode renvoie un nouveau flux de données qui filtre le flux de données source en fonction de la règle transmise . La méthode doit être appelée sur un objet dont le type est Stream<T>
.
Vous pouvez spécifier la règle de filtrage à l'aide d'une fonction lambda , que le compilateur convertira ensuite en Predicate<T>
objet.
Exemples:
Flux chaînés | Explication |
---|---|
|
Ne retenir que les nombres inférieurs à trois |
|
Ne conserver que les nombres supérieurs à zéro |
Stream<T> sorted(Comparator<T>)
méthode
Cette méthode renvoie un nouveau flux de données qui trie les données dans le flux source . Vous transmettez un comparator , qui définit les règles de comparaison de deux éléments du flux de données.
Stream<T> distinct()
méthode
Cette méthode renvoie un nouveau flux de données contenant uniquement les éléments uniques du flux de données source . Toutes les données en double sont supprimées. Exemple:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 2, 2, 2, 3, 4);
Stream<Integer> stream2 = stream.distinct(); // 1, 2, 3, 4, 5
Stream<T> peek(Consumer<T>)
méthode
Cette méthode renvoie un nouveau flux de données , même si les données qu'il contient sont les mêmes que celles du flux source. Mais lorsque l'élément suivant est demandé au flux, la fonction que vous avez transmise à la peek()
méthode est appelée avec lui.
Si vous passez la fonction System.out::println
à la peek()
méthode, alors tous les objets seront affichés lors de leur passage dans le flux.
Stream<T> limit(int n)
méthode
Cette méthode renvoie un nouveau flux de données contenant uniquement les premiers n
éléments du flux de données source . Toutes les autres données sont supprimées. Exemple:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 2, 2, 2, 3, 4);
Stream<Integer> stream2 = stream.limit(3); // 1, 2, 3
Stream<T> skip(int n)
méthode
Cette méthode renvoie un nouveau flux de données qui contient tous les mêmes éléments que le flux source , mais saute (ignore) les premiers n
éléments. Exemple:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 2, 2, 2, 3, 4);
Stream<Integer> stream2 = stream.skip(3); // 4, 5, 2, 2, 2, 3, 4
GO TO FULL VERSION