L’API streams a été introduite avec Java 8 pour permettre la programmation fonctionnelle. Un stream (flux) est une représentation d’une séquence sur laquelle il est possible d’appliquer des opérations.
L’api Stream permet :
- D’optimiser les traitements exécutés grâce au lazyness et à l’utilisation d’opérations de type short-circuiting qui permettent d’interrompre les traitements avant la fin si une condition est atteinte
- Exécuter certains traitements en parallèle à la demande du développeur
Un Stream permet d’exécuter une agrégation d’opérations de manière séquentielle ou en parallèle sur une séquence d’éléments obtenus à partir d’une source dans le but d’obtenir un résultat.
**Exemple :
double tailleMoyenneDesHommes = employes
.stream()
.filter(e -> e.getGenre() == Genre.HOMME)
.mapToInt(e -> e.getTaille())
.average()
.orElse(0);
Un Stream permet d’exécuter des opérations sur un ensemble de données obtenues à partir d’une source afin de générer un résultat.
**Exemple sur une List :
List<String> maListe = Arrays.asList("a1", "a2", "b2", "b1", "c1");
maListe.stream()
.filter(s -> s.startsWith("b"))
.map(String::toUpperCase)
.sorted()
.forEach(System.out::println); }Différence entre une collection et un Stream :
Une collection est une structure qui stocke un ensemble de données en mémoire. Les traitements sur une collection, sans utiliser les Streams, nécessitent de réaliser une itération sur tout ou partie des éléments de la collection par exemple en utilisant l’instruction for.
**Traitement de collection :
List<Personne> personnes = new ArrayList(List.of("Arthur","Pierre"));// ... code pour obtenir une liste de personnes
List<Long> ids = new ArrayList<>(personnes.size());
for(Personne p: personnes){
ids.add(p.getId());
}Avec un Stream, les opérations à réaliser sont décrites mais l’itération ou les itérations pour exécuter ces traitements sont réalisées en interne lors de l’exécution de la méthode terminale du Stream.
**Traitement en mode Stream :
List<Personne> personnes = new ArrayList(List.of("Arthur","Pierre"));
List<Long> ids = personne.stream()
.map(Personne::getId)
.collect(toList());**Tableau des opérations intermédiaires :
| Opération | Rôle | |
|---|---|---|
| filter | Filtrer tous les éléments pour n’inclure dans le Stream de sortie que les éléments qui satisfont le Predicat | |
| map | Renvoyer un Stream qui contient le résultat de la transformation de chaque élément de type T en un élément de type R | |
| mapToxxx(Int, Long or Double) | Renvoyer un Stream qui contient le résultat de la transformation de chaque élément de type T en un type primitif xxx | |
| flatMap | Renvoyer un Stream avec l’ensemble des éléments contenus dans les Stream | |
| flatMapToxxx (Int, Long or Double) | Renvoyer un Stream avec l’ensemble des éléments contenus dans les xxxStream retournés par l’application de la Function sur les éléments de type T. Ainsi chaque élément de type T peut renvoyer zéro, un ou plusieurs éléments de type primitif xxx. | |
| distinct | Renvoyer un Stream | |
| sorted | Renvoyer un Stream dont les éléments sont triés dans un certain ordre. La surcharge sans paramètre tri dans l’ordre naturel : le type T doit donc implémenter l’interface Comparable car c’est sa méthode compareTo() qui est utilisée pour la comparaison des éléments deux à deux La surcharge avec un Comparator l’utilise pour déterminer l’ordre de tri. | |
| peek | Renvoyer les éléments du Stream et leur appliquer le Consumer fourni en paramètre | |
| limit | Renvoyer un Stream qui contient au plus le nombre d’éléments fournis en paramètre | |
| skip | Renvoyer un Stream dont les n premiers éléments ont été ignorés, n correspondant à la valeur fournie en paramètre | |
| sequential | Renvoyer un Stream équivalent dont le mode d’exécution des opérations est séquentiel | |
| parallel | Renvoyer un Stream équivalent dont le mode d’exécution des opérations est en parallèle | |
| unordered | Renvoyer un Stream équivalent dont l’ordre des éléments n’a pas d’importance | |
| onClose | Renvoyer un Stream équivalent dont le handler fourni en paramètre sera exécuté à l’invocation de la méthode close(). L’ordre d’exécution de plusieurs handlers est celui de leur déclaration. Tous les handlers sont exécutés même si un handler précédent à lever une exception. |
**Tableau des opérations terminal :
| Methode | Rôle |
|---|---|
| forEach | Exécuter le Consumer sur chacun des éléments du Stream |
| forEachOrdered | Exécuter le Consumer sur chacun des éléments du Stream en respectant l’ordre de éléments si le Stream en défini un |
| toArray | Object[] toArray() Renvoyer un tableau contenant les éléments du Stream Java<br><A> A[] toArray(IntFunction<A[]> generator)<br>Renvoyer un tableau contenant les éléments du Stream : le tableau est créé par la fonction fournie |
| Reduce | Réaliser une opération de réduction qui accumule les différents éléments du Stream grâce à la fonction fournie |
| collect | Réaliser une opération de réduction avec le Collector fourni en paramètre |
| min | Renvoyer le plus petit élément du Stream selon le Comparator fourni |
| max | Renvoyer le plus grand élément du Stream selon le Comparator fourni |
| count | Renvoyer le nombre d’éléments contenu dans le Stream |
| anyMatch | Retourner un booléen qui indique si au moins un élément valide le Predicate |
| allMatch | Retourner un booléen qui indique si tous les éléments valident le Predicate |
| noneMatch | Retourner un booléen qui indique si aucun élément ne valide le Predicate |
| findFirst | Retourner un Optional qui encapsule le premier élément validant le Predicate s’il existe |
| findAny | Retourner un Optional qui encapsule élément validant le Predicate s’il existe |
| iterator | Renvoyer un Iterator qui permet de réaliser une itération sur tous les éléments en dehors du Stream |
| spliterator | Renvoyer un Spliterator pour les éléments du Stream |
L’API stream est très complète et utile pour plus d’informations voir les sources.
Sources:
https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html https://www.jmdoudoux.fr/java/dej/chap-streams.htm