> ## Content Index
> Fetch the complete content index at: https://www.sfeir.dev/llms.txt
> Use this file to discover other available public pages before exploring further.

# API Stream: Définition
- URL: https://www.sfeir.dev/back/api-stream-definition/
- Published: 2025-01-31T08:45:38.000Z
- Updated: 2025-01-31T08:45:38.000Z
- Description: Introduits avec Java 8, les Streams Java révolutionnent le traitement des données en offrant une approche fonctionnelle élégante. Envie d'en savoir plus ? Je vous explique tout dans cet article !
- Author: Guillaume Fourny
- Tags: Késaco, Back, Java, developpeur, Définition, API

Introduits avec Java 8, les Streams Java révolutionnent le traitement des données en offrant une approche fonctionnelle élégante. Cette API permet de manipuler les collections de manière déclarative grâce à des opérations en chaîne, simplifiant ainsi le code tout en améliorant sa lisibilité.

## Structure des opérations

L'API Stream dans [Java](https://www.sfeir.dev/back/le-langage-java-definition/) fonctionne selon un modèle en trois phases distinctes :

### ✏️ Création du Stream

Plusieurs façons de créer un Stream :

```java
// À partir d'une Collection
List<String> liste = Arrays.asList("a", "b", "c");
Stream<String> stream = liste.stream();

// Création directe
Stream<String> stream = Stream.of("a", "b", "c");

// À partir d'un tableau
String[] array = {"a", "b", "c"};
Stream<String> stream = Arrays.stream(array);

```

Création d'un Stream

### 🔎 Opérations intermédiaires

Ces opérations transforment le Stream et retournent un nouveau Stream :

```java
// Exemples d'opérations intermédiaires
.filter(Predicate<T>) // Filtre les éléments
.map(Function<T,R>)   // Transforme les éléments
.sorted()             // Trie les éléments
.distinct()           // Élimine les doublons
.limit(n)             // Limite le nombre d'éléments

```

Méthodes intermédiaires

### ⌛ Opération terminale

Une opération qui produit un résultat ou un effet de bord :

```java
// Exemples d'opérations terminales
.collect()            // Collecte les résultats
.forEach()            // Parcourt les éléments
.reduce()             // Réduit à une seule valeur
.count()              // Compte les éléments
.anyMatch()           // Vérifie une condition

```

Méthodes terminales

## Caractéristiques importantes

L'API Stream possède des caractéristiques innovantes qui ont contribuées à son succès par rapport aux versions Java précédentes.

### 🦥 Évaluation paresseuse

```java
Stream<String> stream = list.stream()
    .filter(s -> {
        System.out.println("filtrage : " + s);
        return s.startsWith("a");
    })
    .map(s -> {
        System.out.println("mapping : " + s);
        return s.toUpperCase();
    });
```

Lazy loading

Si l'on évalue le code précédent, rien ne s'affichera ! En effet, avec l'API Stream, aucune opération n'est exécutée jusqu'à l'appel d'une opération terminale.

### 🕵️ Pipeline de traitement

```java
long count = personnes.stream()
    .filter(p -> p.getAge() > 18) // Filtre l'élément reçu
    .map(Personne::getNom)        // Transforme l'élément éligible
    .distinct()                   // Supprime les doublons (statefull)
    .count();                     // Compte le nombre d'éléments

```

Pipeline de traitement

Le fait que chaque opération intermédiaire retourne un Stream permet de chainer les appels et ainsi de créer des pipelines de traitement avec une lisibilité de code accrue.

### 🚀 Traitement parallèle

```java
// Conversion d'un stream séquentiel en parallèle
long count = list.stream()
    .parallel()
    .filter(predicate)
    .count();

```

Stream Parallel

### ⚠️ Attention aux opérations bloquantes dans les Streams parallèles

Lors de l'utilisation de `parallelStream()` ou `stream().parallel()`, il est crucial d'éviter les opérations bloquantes qui pourraient dégrader les performances :

```java
// À NE PAS FAIRE ❌
list.parallelStream()
    .map(item -> appelBloquant(item))
    .toList();

// PRÉFÉRER ✅
List<CompletableFuture<String>> asyncResults = list.stream()
    .map(item -> CompletableFuture.supplyAsync(
                ()-> appelBloquant(item),
                Executors.newVirtualThreadPerTaskExecutor())
        )
    .toList();

// Traiter la liste des tâches asynchrone 
// (allOf() / anyOf() / join() etc.)

// ⚠️ Exemple minimaliste qui ne prend pas en compte les échecs
List<String> results = asyncResults.stream()
  .map(CompletableFuture::join)
  .toList();
```

Opérations bloquante dans un Stream

Les opérations bloquantes comme les appels synchrones à des APIs, les opérations I/O peuvent :

- Monopoliser les threads du Common ForkJoinPool
- Réduire significativement les performances
- Créer des deadlocks potentiels

Pour les opérations asynchrones, privilégiez l'utilisation de `CompletableFuture,` de frameworks réactifs ou l'utilisation des [Virtual Thread](https://www.sfeir.dev/back/revolutionnez-votre-programmation-asynchrone-avec-java-21-et-loom/).

Les streams parallèles, et plus largement l'utilisation des threads du Common ForkJoinPool sont réservés à des tâches de calcul.

## 📚 Source de données et Spliterator

Les Streams s'appuient sur un mécanisme de "push" où la source de données pousse les éléments vers le Stream via un Spliterator. Ce dernier est responsable de la traversée et du partitionnement des éléments de la source.

### Connexion avec une base de données

```java
// Dans le repository
public interface UserRepository extends JpaRepository<User, Long> {
    // Spring Data JPA fournit directement les méthodes stream()
    @Query("SELECT u FROM User u")
    Stream<User> streamAllUsers();
}

// Dans le service
@Service
@RequiredArgsConstructor
public class UserService {
    private final UserRepository userRepository;

    @Transactional(readOnly = true)
    public void processUsers() {
        try (var userStream = userRepository.streamAllUsers()) {
            userStream
                .filter(user -> user.getAge() > 18)
                .map(User::getName)
                .forEach(System.out::println);
        } // Le Stream est automatiquement fermé
    }
}

```

Streamer les résultats d'une requête en base de données

Le `try-with-resources` est important pour s'assurer que la session Hibernate est correctement fermée après l'utilisation du Stream.

L'avantage par rapport à un findAll qui renverrai une liste est qu'ici, nous n'avons qu'un seul objet en mémoire à l'instant T.

## 🗝️ Points clés à retenir

1. **Usage Unique** : Un Stream ne peut être utilisé qu'une seule fois. Après une opération terminale, le Stream est fermé.
2. **Immutabilité** : Les opérations de Stream ne modifient pas la source de données originale.
3. **Chaînage** : Les opérations peuvent être chaînées pour créer des pipelines de traitement complexes.
4. **Short-Circuiting** : Certaines opérations (comme findFirst(), limit()) peuvent arrêter le traitement avant de parcourir tous les éléments.

## Exemple complet

```java
List<String> resultat = personnes.stream()
    .filter(p -> p.getAge() > 18)  // Filtre les majeurs
    .map(Personne::getNom)         // Extrait les noms
    .sorted()                      // Trie par ordre alphabétique
    .distinct()                    // Élimine les doublons
    .toList();                     // Collecte dans une liste imutable

```

Exemple API Stream

Cette structure permet une manipulation efficace et expressive des données, particulièrement adaptée aux traitements complexes sur des collections.

### **Conclusion**

Les Streams Java, introduits avec Java 8, ont transformé la manière dont les développeurs manipulent les collections de données. Grâce à une approche fonctionnelle, des opérations en chaîne et un traitement optimisé, cette API permet d’écrire un code plus **lisible, concis et performant**.

L’évaluation paresseuse et le support du **traitement parallèle** offrent des gains significatifs en efficacité, à condition de bien maîtriser leur utilisation pour éviter les pièges des opérations bloquantes.

Que ce soit pour le filtrage, la transformation ou la réduction des données, les Streams constituent un **outil puissant et incontournable** pour tout développeur Java moderne. 🚀

👉 **Et vous, utilisez-vous déjà les Streams dans vos projets ?** 😊

*Si vous souhaitez en savoir plus sur l'histoire de Java, découvrez cet article 👇*

[Il était une fois... JavaJava, un langage de programmation qui approche la trentaine. Vieux langage poussiéreux ou rock star qui en a encore sous le capot ?![](https://storage.ghost.io/c/0b/31/0b31478e-a66a-46f1-8c34-d44388e21192/content/images/icon/plume-point-140.png)sfeir.dev - Le média incontournable pour les passionnés de tech et d'intelligence artificielleErwan Le Tutour![](https://storage.ghost.io/c/0b/31/0b31478e-a66a-46f1-8c34-d44388e21192/content/images/thumbnail/java.png)](https://www.sfeir.dev/back/il-etait-une-fois-java/)