Le Tutoriel de Java Stream
1. Stream
Java 8 introduit un nouveau concept appelé Stream (le flux). La première fois que vous lisez sur l'API Stream, cela peut provoquer une confusion, car son nom est similaire à InputStream et OutputStream. Mais Java 8 Stream est quelque chose de complètement différent. Stream est une monade qui joue donc un rôle important dans l'introduction de la programmation fonctionnelle dans Java.
Avant de commencer cet article, je vous recommande de vous renseigner sur les functional interfaces et certaines functional interfaces courantes telles que: Supplier, Consumer, Predicate. Ci-dessous mes articles:
En programmation fonctionnelle, une monade est une structure qui représente un calcul lequel nécessite une séquence d'étapes liées entre elles. Vous pouvez consulter l'exemple de monade ci-dessous:
List<String> myList = Arrays.asList("a1", "a2", "b1", "c2", "c1");
myList
.stream() // (1) return a Stream
.filter(s -> s.startsWith("c")) // (2) return a new Stream
.map(String::toUpperCase) // (3) return a new Stream
.sorted() // (4) return a new Stream
.forEach(System.out::println); // (5)
Output:
C1
C2
- Créer un Streamà partir d'un objet List.
- Créer un nouveau Streamà partir du Streamprécédent et inclure uniquement les éléments initiés par la lettre "c".
- Créer un nouveau Streamà partir du Streamprécédent avec tous les éléments convertis en majuscules.
- Créer un nouveau Stream à partir du Stream précédent en triant les éléments.
- Imprimer les éléments du dernier Stream.
Dans l'exemple précédent, les étapes (2) à (4) sont des opérations intermédiaires, car elles renvoient un objet Stream. Vous pouvez donc appeler une autre méthode de Stream sans avoir à la terminer par un point-virgule.
Une opération de terminal est une méthode qui renvoie void ou renvoie un type différent de Stream. Dans l'exemple précédent, l'étape 5 est une opération de terminal car la méthode Stream.forEach renvoie void.
Ci-dessous les caractéristiques et avantages de Java 8 Stream:
- Pas de stockage. Un Stream n'est pas une structure de données, mais une vue d'une source de données (qui peut être un tableau, une liste ou une I/O Channel,...).
- Un Stream est de nature fonctionnelle. Les modifications apportées à un Streamne modifieront pas les sources de données. Par exemple, filtrer un Stream ne supprimera aucun élément, mais créera un nouveau Stream incluant les éléments filtrés.
- Exécution paresseuse. Les opérations sur un Streamne seront pas exécutées immédiatement. Ils seront exécutés lorsque les utilisateurs ont absolument besoin de résultats.
- Consommable. Les éléments d'un Stream ne sont visités qu'une seule fois au cours de la vie d'un Stream. Une fois traversé, un Stream est invalidé, tout comme un Iterator. Il faut régénérer un nouveau Stream si vous souhaitez traverser à nouveau le Stream.
Observer l'illustration ci-dessous pour mieux comprendre la manière de fonction de Stream.
- Créer un Streamà partir d'une collection.
- Filtrer les couleurs autres que le rouge.
- Peindre le rose pour les triangles.
- Filtrer les formes qui ne sont pas carrées.
- Calculer la superficie totale.
La classe Employee sera présente dans certains exemples de cet article:
Employee.java
package org.o7planning.stream.ex;
public class Employee {
private String name;
private float salary;
private String gender; // "M", "F"
public Employee(String name, float salary, String gender) {
this.name = name;
this.salary = salary;
this.gender = gender;
}
public String getName() {
return name;
}
public float getSalary() {
return salary;
}
public String getGender() {
return gender;
}
public boolean isFemale() {
return "F".equals(this.getGender());
}
}
2. Stream.filter(Predicate)
Renvoyer un Stream constitué d'éléments de ce Stream correspondant au Predicatedonné.
Stream<T> filter(Predicate<? super T> predicate)
Exemple: A partir d'une liste d'employés (Employee), imprimer une liste d'employées dont le salaire est supérieur à 2500.
Stream_filter_ex1.java
package org.o7planning.stream.ex;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class Stream_filter_ex1 {
public static void main(String[] args) {
Employee john = new Employee("John P.", 1500, "M");
Employee sarah = new Employee("Sarah M.", 2000, "F");
Employee charles = new Employee("Charles B.", 1700, "M");
Employee mary = new Employee("Mary T.", 5000, "F");
Employee sophia = new Employee("Sophia B.", 7000, "F");
List<Employee> employees = Arrays.asList(john, sarah, charles, mary, sophia);
// Employee is Female and salary > 2500
Predicate<Employee> predicate = e -> e.isFemale() && e.getSalary() > 2500;
employees //
.stream() //
.filter(predicate) //
.forEach(e -> System.out.println(e.getName()+ " : " + e.getSalary()));
}
}
Output:
Mary T. : 5000.0
Sophia B. : 7000.0
Si une méthode n'est pas statique (méthode non statique), ne dispose pas de paramètres et renvoie une valeur boolean, sa référence est alors considérée comme un Predicate. (Voir l'explication dans mon article sur Java Predicate).
Exemple: Créer un Predicate à partir de la référence d'une méthode:
Predicate<Employee> p = Employee::isFemale;
// Same as:
Predicate<Employee> p = employee -> employee.isFemale();
Stream_filter_ex2.java
package org.o7planning.stream.ex;
import java.util.Arrays;
import java.util.List;
public class Stream_filter_ex2 {
public static void main(String[] args) {
Employee john = new Employee("John P.", 1500, "M");
Employee sarah = new Employee("Sarah M.", 2000, "F");
Employee charles = new Employee("Charles B.", 1700, "M");
Employee mary = new Employee("Mary T.", 5000, "F");
Employee sophia = new Employee("Sophia B.", 7000, "F");
List<Employee> employees = Arrays.asList(john, sarah, charles, mary, sophia);
employees //
.stream() //
.filter(Employee::isFemale) //
.forEach(e -> System.out.println(e.getName()+ " : " + e.getSalary()));
}
}
Output:
Sarah M. : 2000.0
Mary T. : 5000.0
Sophia B. : 7000.0
3. Stream.sorted(Comparator)
Renvoyer un Stream constitué d'éléments de ce Stream, triés en fonction du Comparatorfourni.
Stream<T> sorted(Comparator<? super T> comparator)
- Le Tutoriel de Java Comparator
Exemple: Trier des salariés par ordre croissant de salaire:
Stream_sort_ex1.java
package org.o7planning.stream.ex;
import java.util.Arrays;
import java.util.List;
public class Stream_sort_ex1 {
public static void main(String[] args) {
Employee john = new Employee("John P.", 1500, "M");
Employee sarah = new Employee("Sarah M.", 2000, "F");
Employee charles = new Employee("Charles B.", 1700, "M");
Employee mary = new Employee("Mary T.", 5000, "F");
Employee sophia = new Employee("Sophia B.", 7000, "F");
List<Employee> employees = Arrays.asList(john, sarah, charles, mary, sophia);
employees //
.stream() //
.sorted (
(e1,e2) -> (int) (e1.getSalary() - e2.getSalary())
) //
.forEach(e -> System.out.println(e.getSalary() + " : " + e.getName()));
}
}
Output:
1500.0 : John P.
1700.0 : Charles B.
2000.0 : Sarah M.
5000.0 : Mary T.
7000.0 : Sophia B.
Exemple: Trier l'employé par genre et salaire:
Stream_sort_ex2.java
package org.o7planning.stream.ex;
import java.util.Arrays;
import java.util.List;
public class Stream_sort_ex2 {
public static void main(String[] args) {
Employee john = new Employee("John P.", 1500, "M");
Employee sarah = new Employee("Sarah M.", 2000, "F");
Employee charles = new Employee("Charles B.", 1700, "M");
Employee mary = new Employee("Mary T.", 5000, "F");
Employee sophia = new Employee("Sophia B.", 7000, "F");
List<Employee> employees = Arrays.asList(john, sarah, charles, mary, sophia);
employees //
.stream() //
.sorted (
(e1,e2) -> {
int v = e1.getGender().compareTo(e2.getGender());
if(v == 0) {
v = (int) (e1.getSalary() - e2.getSalary());
}
return v;
}
) //
.forEach(e -> System.out.println(e.getGender()+ " : "+ e.getSalary() + " : " + e.getName()));
}
}
Output:
F : 2000.0 : Sarah M.
F : 5000.0 : Mary T.
F : 7000.0 : Sophia B.
M : 1500.0 : John P.
M : 1700.0 : Charles B.
4. Stream.map(Function)
Renvoyer un nouveau Stream constitué de résultats de l'application de Functiondonnée aux éléments de ce Stream.
<R> Stream<R> map(Function<? super T,? extends R> mapper)
Exemple: Convertir une liste de String(s) en majuscules.
Stream_map_ex1.java
package org.o7planning.stream.ex;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class Stream_map_ex1 {
public static void main(String[] args) {
List<String> list = Arrays.asList("a", "b", "c", "d", "e");
List<String> newList = list //
.stream() // a Stream
.map(s -> s.toUpperCase()) // a new Stream
.collect(Collectors.toList()); // Stream => List
System.out.println(list); // [a, b, c, d, e]
System.out.println(newList); // [A, B, C, D, E]
}
}
Si une méthode est non statique (méthode non statique), sans paramètre et renvoie une valeur, sa référence est considérée comme une Function. (Voir plus d'explications dans mon article sur la Java Function).
// Create a Function from a method reference:
Function<String, String> f1 = String::toUpperCase;
// Same as:
Function<String, String> f2 = s -> s.toUpperCase();
Stream_map_ex2.java
package org.o7planning.stream.ex;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class Stream_map_ex2 {
public static void main(String[] args) {
List<String> list = Arrays.asList("a", "b", "c", "d", "e");
List<String> newList = list //
.stream() // a Stream
.map(String::toUpperCase) // a new Stream
.collect(Collectors.toList()); // Stream => List
System.out.println(list); // [a, b, c, d, e]
System.out.println(newList); // [A, B, C, D, E]
}
}
Exemple: Doubler le salaire pour chaque employé d'une liste:
Stream_map_ex3.java
package org.o7planning.stream.ex;
import java.util.Arrays;
import java.util.List;
public class Stream_map_ex3 {
public static void main(String[] args) {
Employee john = new Employee("John P.", 1500, "M");
Employee sarah = new Employee("Sarah M.", 2000, "F");
Employee charles = new Employee("Charles B.", 1700, "M");
Employee mary = new Employee("Mary T.", 5000, "F");
Employee sophia = new Employee("Sophia B.", 7000, "F");
List<Employee> employees = Arrays.asList(john, sarah, charles, mary, sophia);
employees //
.stream() // a Stream.
.map((e) -> new Employee(e.getName(), e.getSalary()* 2, e.getGender())) // a new Stream.
.forEach(c -> System.out.println(c.getName()+ " : " + c.getSalary()));
}
}
Output:
John P. : 3000.0
Sarah M. : 4000.0
Charles B. : 3400.0
Mary T. : 10000.0
Sophia B. : 14000.0
Java Basic
- Personnaliser le compilateur Java pour traiter votre annotation (Annotation Processing Tool)
- Programmation Java pour l'équipe utilisant Eclipse et SVN
- Le Tutoriel de Java WeakReference
- Le Tutoriel de Java PhantomReference
- Tutoriel sur la compression et la décompression Java
- Configuration d'Eclipse pour utiliser le JDK au lieu de JRE
- Méthodes Java String.format() et printf()
- Syntaxe et nouvelles fonctionnalités de Java 8
- Expression régulière en Java
- Tutoriel de programmation Java multithreading
- Bibliothèques de pilotes JDBC pour différents types de bases de données en Java
- Tutoriel Java JDBC
- Obtenir des valeurs de colonne automatiquement incrémentées lors de l'insertion d'un enregistrement à l'aide de JDBC
- Le Tutoriel de Java Stream
- Le Tutoriel de Java Functional Interface
- Introduction à Raspberry Pi
- Le Tutoriel de Java Predicate
- Classe abstraite et interface en Java
- Modificateurs d'accès en Java
- Le Tutoriel de Java Enum
- Le Tutoriel de Java Annotation
- Comparer et trier en Java
- Le Tutoriel de Java String, StringBuffer et StringBuilder
- Tutoriel de gestion des exceptions Java
- Le Tutoriel de Java Generics
- Manipulation de fichiers et de répertoires en Java
- Le Tutoriel de Java BiPredicate
- Le Tutoriel de Java Consumer
- Le Tutoriel de Java BiConsumer
- Qu'est-ce qui est nécessaire pour commencer avec Java?
- L'histoire de Java et la différence entre Oracle JDK et OpenJDK
- Installer Java sur Windows
- Installer Java sur Ubuntu
- Installer OpenJDK sur Ubuntu
- Installer Eclipse
- Installer Eclipse sur Ubuntu
- Le Tutoriel Java pour débutant
- Histoire des bits et des bytes en informatique
- Types de données dans Java
- Opérations sur les bits
- Le Tutoriel de instruction Java If else
- Le Tutoriel de instruction Java Switch
- Les Boucles en Java
- Les Tableaux (Array) en Java
- JDK Javadoc au format CHM
- Héritage et polymorphisme en Java
- Le Tutoriel de Java Function
- Le Tutoriel de Java BiFunction
- Exemple de Java encoding et decoding utilisant Apache Base64
- Le Tutoriel de Java Reflection
- Invocation de méthode à distance en Java
- Le Tutoriel de Java Socket
- Quelle plate-forme devez-vous choisir pour développer des applications de bureau Java?
- Le Tutoriel de Java Commons IO
- Le Tutoriel de Java Commons Email
- Le Tutoriel de Java Commons Logging
- Comprendre Java System.identityHashCode, Object.hashCode et Object.equals
- Le Tutoriel de Java SoftReference
- Le Tutoriel de Java Supplier
- Programmation orientée aspect Java avec AspectJ (AOP)
Show More
- Tutoriels de programmation Java Servlet/JSP
- Tutoriels de Java Collections Framework
- Tutoriels Java API pour HTML & XML
- Tutoriels Java IO
- Tutoriels Java Date Time
- Tutoriels Spring Boot
- Tutoriels Maven
- Tutoriels Gradle
- Tutoriels Java Web Service
- Tutoriels de programmation Java SWT
- Tutoriels de JavaFX
- Tutoriels Java Oracle ADF
- Tutoriels Struts2
- Tutoriels Spring Cloud