Java permet de construire un flux de traitement (ou un pipeline) qui contient un ensemble d'étapes (ou opérations) qui s’appliquent en série sur les éléments d’une source de données.
Les opérations qui peuvent être appliquées sur un flux sont de deux types :
des
opérations intermédiaires
(
intermediate operations)
ou des
opérations terminales
(
terminal operation).
-
Le flux de traitement commence par créer une instance de l’interface
java.util.stream.Stream
à partir d’une source de données (collection, tableau, ensemble d’éléments).
Exemples :
// Creates a stream from a set of values.
Stream<Integer> integerStream1 = Stream.of(Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3));
// Creates a stream from an array.
Integer[] values = {1, 2, 3};
Stream<Integer> integerStream2 = Stream.of(values);
Stream<Integer> integerStream3 = Arrays.stream(values);
// Creates a stream from a list.
Stream<Integer> integerStream4 = Arrays.asList(values).stream();
-
Les opérations intermédiaires du pipeline produisent une nouvelle instance de l’interface
Stream
.
Exemples :
Stream<Integer> integerStream1 = Stream.of(Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3));
// the intermediate operation "filter" transform a stream into another stream
Stream<Integer> integerStream2 = integerStream1.filter(i -> i%2==0);
// the intermediate operation "map" transform a stream into another stream
Stream<String> integerStream3 = integerStream2.map(i -> String.valueOf(i));
-
L’opération terminale du pipeline produit un résultat ou un effet de bord.
Cette opération ferme le flux.
Exemples :
// the terminal operation "count" produces a result
Long value = Stream.of(Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3)).count();
// the terminal operation "forEach" produces a side-effect
Stream.of(Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3)).forEach(System.out::println);
-
Les opérations intermédiaires sont exécutées uniquement si l'opération terminale est initiée.
Autrement dit, les opérations intermédiaires d’un pipeline ne seront jamais exécutées si le pipeline ne declare pas une operation terminale.
Aussi les éléments de la source de données sont consommés uniquement au besoin.
Exemples :
// filter and limit are intermediate operations, they won't be applied now
// the intermediate operation "limit" will restrict the processing of the
// elements of the stream to only the specified number
Stream<Integer> integerStream1 = Stream.of(1, 2, 3, 4, 5, 6).filter(i -> i % 2 == 0).limit(2);
// forEach is a terminal operation, all intermediate operations along with the
// terminal operation will be applied
integerStream1.forEach(System.out::println);
-
Une seule opération terminale peut s'appliquer sur une instance
Stream
.
Si une deuxième opération (intermédiaire ou terminale) est appliquée sur une instance Stream
après l'exécution de l'opération terminale, une exception va être déclenchée :
"java.lang.IllegalStateException: stream has already been operated upon or closed"
.
Exemples :
Stream<Integer> integerStream1 = Stream.of(Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3));
// OK: first operation to be applied on the "integerStream1" instance
Stream<Integer> integerStream2 = integerStream1.filter(i -> i%2==0);
// throws the exception: java.lang.IllegalStateException: stream has already been operated upon or closed
Stream<Integer> integerStream3 = integerStream1.filter(i -> i%2==0);
// throws the exception: java.lang.IllegalStateException: stream has already been operated upon or closed
long i = integerStream1.count();
// OK: first operation to be applied on the "integerStream2" instance
System.out.println(integerStream2.count());
// throws the exception: java.lang.IllegalStateException: stream has already been operated upon or closed
System.out.println(integerStream2.count());
-
La chaine des operations qui peuvent être appliquées sur une séquence des éléments peuvent être exécutées en série (par défaut) ou en parallèle.
Exemples :
Integer[] values = {1, 2, 3};
// stream returns a sequential Stream
Arrays.stream(values).forEach(System.out::println);
Arrays.asList(values).stream().forEach(System.out::println);
// parallel/parallelStream returns a possibly parallel Stream
Arrays.stream(values).parallel().forEach(System.out::println);
Arrays.asList(values).parallelStream().forEach(System.out::println);