Java 8 Stream
Nouveautés de Java 8
L'API Java 8 a ajouté une nouvelle abstraction appelée Stream, qui vous permet de traiter les données de manière déclarative.
Stream fournit une abstraction de haut niveau pour les opérations et expressions de collections Java d'une manière intuitive, similaire à l'interrogation de données dans une base de données avec des instructions SQL.
L'API Stream peut grandement améliorer la productivité des programmeurs Java, leur permettant d'écrire du code efficace, propre et concis.
Ce style traite la collection d'éléments à traiter comme un flux. Le flux est transmis dans un pipeline et peut être traité aux nœuds du pipeline, tels que le filtrage, le tri, l'agrégation, etc.
Le flux d'éléments passe par des opérations intermédiaires dans le pipeline, et finalement les résultats de traitement précédents sont obtenus par une opération terminale.
+--------------------+ +------+ +------+ +---+ +-------+
| stream of elements +-----> |filter+-> |sorted+-> |map+-> |collect|
+--------------------+ +------+ +------+ +---+ +-------+
Le processus ci-dessus est converti en code Java comme suit :
List<Integer> transactionsIds =
widgets.stream()
.filter(b -> b.getColor() == RED)
.sorted((x,y) -> x.getWeight() - y.getWeight())
.mapToInt(Widget::getWeight)
.sum();
Qu'est-ce qu'un Stream ?
Stream est une file d'éléments provenant d'une source de données et prend en charge des opérations d'agrégation.
- Les éléments sont des objets d'un type spécifique, formant une file. Stream en Java ne stocke pas les éléments ; au lieu de cela, il les calcule à la demande.
- Source de donnéesLa source du flux. Elle peut être une collection, un tableau, un canal d'E/S, un générateur, etc.
- Opérations d'agrégationOpérations similaires aux instructions SQL, telles que filter, map, reduce, find, match, sorted, etc.
Contrairement aux opérations précédentes sur les Collection, les opérations Stream ont deux caractéristiques de base :
- Mise en pipelineMise en pipeline : Les opérations intermédiaires renvoient toutes l'objet Stream lui-même. Cela permet de chaîner plusieurs opérations dans un pipeline, comme dans un style fluide. Cela permet d'optimiser les opérations, telles que l'évaluation paresseuse et le court-circuit.
- Itération interneItération interne : Auparavant, le parcours de collection était effectué via Iterator ou For-Each, en itérant explicitement en dehors de la collection, ce que l'on appelle l'itération externe. Stream fournit une méthode d'itération interne, implémentée via le patron Visiteur.
Génération de Streams
Dans Java 8, l'interface Collection possède deux méthodes pour générer des flux :
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
forEach
Stream fournit une nouvelle méthode 'forEach' pour parcourir chaque donnée du flux. L'extrait de code suivant utilise forEach pour afficher 10 nombres aléatoires :
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
map
La méthode map est utilisée pour mapper chaque élément à son résultat correspondant. L'extrait de code suivant utilise map pour afficher les carrés des éléments :
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
filter
La méthode filter est utilisée pour filtrer les éléments en fonction d'une condition définie. L'extrait de code suivant utilise la méthode filter pour filtrer les chaînes vides :
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
long count = strings.stream().filter(string -> string.isEmpty()).count();
limit
La méthode limit est utilisée pour obtenir un flux avec une quantité spécifiée. L'extrait de code suivant utilise la méthode limit pour imprimer 10 éléments de données :
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
sorted
La méthode sorted est utilisée pour trier le flux. L'extrait de code suivant utilise la méthode sorted pour trier les 10 nombres aléatoires de sortie :
Random random = new Random();
random.ints().limit(10).sorted().forEach(System.out::println);
Programme parallèle
parallelStream est une méthode alternative pour le traitement parallèle des flux. Dans l'exemple suivant, nous utilisons parallelStream pour afficher le nombre de chaînes vides :
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
long count = strings.parallelStream().filter(string -> string.isEmpty()).count();
Nous pouvons facilement basculer entre l'exécution séquentielle et parallèle.
Collectors
La classe Collectors implémente de nombreuses opérations de réduction, telles que la conversion de flux en collections et l'agrégation d'éléments. Collectors peut être utilisé pour renvoyer des listes ou des chaînes :
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
System.out.println("Liste filtrée :" + filtered);
String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("Chaînes fusionnées :" + mergedString);
Statistiques
De plus, certains collecteurs qui produisent des résultats statistiques sont également très utiles. Ils sont principalement utilisés sur des types primitifs tels que int, double et long, et peuvent être utilisés pour produire des résultats statistiques comme les suivants.
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();
System.out.println("Le plus grand nombre dans la liste :" + stats.getMax());
System.out.println("Le plus petit nombre dans la liste :" + stats.getMin());
System.out.println("Somme de tous les nombres :" + stats.getSum());
System.out.println("Moyenne :" + stats.getAverage());
Exemple complet de Stream
Placez le code suivant dans le fichier Java8Tester.java :
Fichier Java8Tester.java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.Map;
public class Java8Tester {
public static void main(String args[]){
System.out.println("Utilisation de Java 7:");
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
System.out.println("Liste:" +strings);
long count = getCountEmptyStringUsingJava7(strings);
System.out.println("Nombre de chaînes vides:" + count);
count = getCountLength3UsingJava7(strings);
System.out.println("Nombre de chaînes de longueur 3:" + count);
List<String> filtered = deleteEmptyStringsUsingJava7(strings);
System.out.println("Liste filtrée :" + filtered);
String mergedString = getMergedStringUsingJava7(strings,", ");
System.out.println("Chaînes fusionnées :" + mergedString);
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
List<Integer> squaresList = getSquares(numbers);
System.out.println("Liste des nombres carrés :" + squaresList);
List<Integer> integers = Arrays.asList(1,2,13,4,15,6,17,8,19);
System.out.println("Liste :" +integers);
System.out.println("Le plus grand nombre de la liste :" + getMax(integers));
System.out.println("Le plus petit nombre de la liste :" + getMin(integers));
System.out.println("Somme de tous les nombres :" + getSum(integers));
System.out.println("Moyenne :" + getAverage(integers));
System.out.println("Nombres aléatoires :");
Random random = new Random();
for(int i=0; i < 10; i++){
System.out.println(random.nextInt());
}
System.out.println("Utilisation de Java 8 :");
System.out.println("Liste:" +strings);
count = strings.stream().filter(string->string.isEmpty()).count();
System.out.println("Nombre de chaînes vides:" + count);
count = strings.stream().filter(string -> string.length() == 3).count();
System.out.println("Nombre de chaînes de longueur 3:" + count);
filtered = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.toList());
System.out.println("Liste filtrée :" + filtered);
mergedString = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("Chaînes fusionnées :" + mergedString);
squaresList = numbers.stream().map( i ->i*i).distinct().collect(Collectors.toList());
System.out.println("Liste des carrés : " + squaresList);
System.out.println("Liste :" +integers);
IntSummaryStatistics stats = integers.stream().mapToInt((x) ->x).summaryStatistics();
System.out.println("Le plus grand nombre dans la liste :" + stats.getMax());
System.out.println("Le plus petit nombre dans la liste :" + stats.getMin());
System.out.println("Somme de tous les nombres :" + stats.getSum());
System.out.println("Moyenne :" + stats.getAverage());
System.out.println("Nombres aléatoires :");
random.ints().limit(10).sorted().forEach(System.out::println);
count = strings.parallelStream().filter(string -> string.isEmpty()).count();
System.out.println("Nombre de chaînes vides:" + count);
}
private static int getCountEmptyStringUsingJava7(List<String> strings){
int count = 0;
for(String string: strings){
if(string.isEmpty()){
count++;
}
}
return count;
}
private static int getCountLength3UsingJava7(List<String> strings){
int count = 0;
for(String string: strings){
if(string.length() == 3){
count++;
}
}
return count;
}
private static List<String> deleteEmptyStringsUsingJava7(List<String> strings){
List<String> filteredList = new ArrayList<String>();
for(String string: strings){
if(!string.isEmpty()){
filteredList.add(string);
}
}
return filteredList;
}
private static String getMergedStringUsingJava7(List<String> strings, String separator){
StringBuilder stringBuilder = new StringBuilder();
for(String string: strings){
if(!string.isEmpty()){
stringBuilder.append(string);
stringBuilder.append(separator);
}
}
String mergedString = stringBuilder.toString();
return mergedString.substring(0, mergedString.length()-2);
}
private static List<Integer> getSquares(List<Integer> numbers){
List<Integer> squaresList = new ArrayList<Integer>();
for(Integer number: numbers){
Integer square = new Integer(number.intValue() * number.intValue());
if(!squaresList.contains(square)){
squaresList.add(square);
}
}
return squaresList;
}
private static int getMax(List<Integer> numbers){
int max = numbers.get(0);
for(int i=1;i < numbers.size();i++){
Integer number = numbers.get(i);
if(number.intValue() > max){
max = number.intValue();
}
}
return max;
}
private static int getMin(List<Integer> numbers){
int min = numbers.get(0);
for(int i=1;i < numbers.size();i++){
Integer number = numbers.get(i);
if(number.intValue() < min){
min = number.intValue();
}
}
return min;
}
private static int getSum(List numbers){
int sum = (int)(numbers.get(0));
for(int i=1;i < numbers.size();i++){
sum += (int)numbers.get(i);
}
return sum;
}
private static int getAverage(List<Integer> numbers){
return getSum(numbers) / numbers.size();
}
}
L'exécution du script ci-dessus produit la sortie suivante :
$ javac Java8Tester.java
$ java Java8Tester
使用 Java 7:
列表: [abc, , bc, efg, abcd, , jkl]
空字符数量为: 2
字符串长度为 3 的数量为: 3
筛选后的列表: [abc, bc, efg, abcd, jkl]
合并字符串: abc, bc, efg, abcd, jkl
平方数列表: [9, 4, 49, 25]
列表: [1, 2, 13, 4, 15, 6, 17, 8, 19]
列表中最大的数 : 19
列表中最小的数 : 1
所有数之和 : 85
平均数 : 9
随机数:
-393170844
-963842252
447036679
-1043163142
-881079698
221586850
-1101570113
576190039
-1045184578
1647841045
使用 Java 8:
列表: [abc, , bc, efg, abcd, , jkl]
空字符串数量为: 2
字符串长度为 3 的数量为: 3
筛选后的列表: [abc, bc, efg, abcd, jkl]
合并字符串: abc, bc, efg, abcd, jkl
Squares List: [9, 4, 49, 25]
列表: [1, 2, 13, 4, 15, 6, 17, 8, 19]
列表中最大的数 : 19
列表中最小的数 : 1
所有数之和 : 85
平均数 : 9.444444444444445
随机数:
-1743813696
-1301974944
-1299484995
-779981186
136544902
555792023
1243315896
1264920849
1472077135
1706423674
空字符串的数量为: 2
Nouveautés de Java 8
Autres extensions