To `Gather` or not to `Gather`? That is the question.

Mais de quoi va-t-on parler ? De java. Oui je préfère le dire dès le début. Cet article va parler de Java ! Les gatherers sont le premier ajout d'importance à l’API java.util.Streams, depuis sa sortie, et on parle de 2014. Cela signifie qu’il ne s’était pas passé grand-chose depuis environ longtemps. Arrivés en preview en Java 22, ils le sont toujours en Java 24. Table des matières Remise à niveau Rappels Collectors vs Gatherers L'interface Gatherer Let's code! On recode la méthode filter Un stream avec un index !? Un groupingBy, mais pas terminal. Et maintenant, on fusionne des streams! Remise à niveau Même si on ne va pas faire une revue complète de l'API java.util.Streams, je vous propose de commencer par un petit quizz, tranquilles, posés. Quiz 1/3 1 public class Quizz { 2 public static void main(String[] args) { 3 getPeople() 4 .map(person -> person.getName()) 5 .toList(); 6 } 7 } Admettons que la méthode getPeople renvoie une instance de stream de 10 objets de type Person. Ici, le code est simple, on applique la méthode map qui prend en paramètre une Function, qui transforme une instance de Person en String en renvoyant le résultat de la méthode Person.getName(). La question est : Combien de fois la ligne 4 est-elle invoquée ? ① 1 fois ? ② 10 fois ? ③ Non Jérôme, elle n'est pas invoquée la ligne 4. ④ It depends! spoiler Vous êtes-vous dit qu’il y avait plusieurs bonnes réponses ? La bonne réponse est: ④ It depends! En réalité, la question était mal posée. La question, aurait du être : "Est-ce que la méthode map est invoquée une fois, 10 fois, ainsi de suite ?" ou "Est-ce que la fonction qui est passée en paramètre de la méthode map est invoquée ?" La méthode map, est bien appelée une seule fois, par contre, la fonction qui lui est passée en paramètre, elle, est bien invoquée 10 fois. Il faut systématiquement différencier les méthodes de l’API Stream, qui ne font que de la configuration de pipeline, et les fonctions/predicats/... qu’on leur passe. Quiz 2/3 Bon, ok, on a compris. À partir de maintenant, la question portera systématiquement sur le nombre d’invocations de la Function passée en paramètre de la méthode map. 1 public class Quizz { 2 public static void main(String[] args) { 3 getPeople() 4 .map(person -> person.getName()); 5 } 6 } La question est : Combien de fois la ligne 4 est-elle invoquée ? ① 1 fois ? ② 10 fois ? ③ Non Jérôme, elle n'est pas invoquée la ligne 4. spoiler La bonne réponse est : ③ Non Jérôme, elle n’est pas invoquée la ligne 4. Dans un stream, il y a deux types d’opérations : Des opérations intermédiaires. Des opérations finales. Les opérations intermédiaires ne font que configurer un pipeline d’exécution, elles ne déclenchent rien. Tant qu’on n’a pas appelé une méthode finale sur un stream, il ne se passe rien du tout. Quiz 3/3 1 public class Quiz { 2 public static void main(String[] args) { 3 getPeople() 4 .map(person -> person.getName()) 5 .count(); 6 } 7 } La question est : Combien de fois la ligne 4 est-elle invoquée ? ① 1 fois ? ② 10 fois ? ③ Non Jérôme, elle n'est pas invoquée la ligne 4. spoiler La bonne réponse est : ③ Non Jérôme, elle n’est pas invoquée la ligne 4. Eeeeeeet oui, l’API stream est intelligente, et parmi les opérations terminales, il y en a certaines qui possèdent des shortcuts. Et c'est le cas de la méthode count qui est capable d’évaluer si toutes les opérations qui ont été exécutées avant elle peuvent avoir un impact sur la cardinalité de ce qu’il y a en sortie. Ici, une seule opération map n’aura aucun impact sur la cardinalité, et donc, inutile de l’invoquer, ça n’a aucun intérêt. On n’a pas besoin de transformer des personnes en chaînes de caractères pour savoir qu’il y en à 10. C'est assez important de comprendre que vous n'avez pas de garantie d'invocation. Et si, par exemple, vous faites partie de la team peek-

Mar 24, 2025 - 10:17
 0
To `Gather` or not to `Gather`? That is the question.

Mais de quoi va-t-on parler ?

De java. Oui je préfère le dire dès le début. Cet article va parler de Java !
logo java

Les gatherers sont le premier ajout d'importance à l’API java.util.Streams, depuis sa sortie, et on parle de 2014. Cela signifie qu’il ne s’était pas passé grand-chose depuis environ longtemps.
Arrivés en preview en Java 22, ils le sont toujours en Java 24.

Table des matières

  • Remise à niveau
  • Rappels
  • Collectors vs Gatherers
  • L'interface Gatherer
  • Let's code!
    • On recode la méthode filter
    • Un stream avec un index !?
    • Un groupingBy, mais pas terminal.
    • Et maintenant, on fusionne des streams!

Remise à niveau

Même si on ne va pas faire une revue complète de l'API java.util.Streams, je vous propose de commencer par un petit quizz, tranquilles, posés.

Shakespeare posant une question

Quiz 1/3

1 public class Quizz {
2    public static void main(String[] args) {
3        getPeople()
4            .map(person -> person.getName())
5            .toList();
6    }
7 }

Admettons que la méthode getPeople renvoie une instance de stream de 10 objets de type Person.

Ici, le code est simple, on applique la méthode map qui prend en paramètre une Function, qui transforme une instance de Person en String en renvoyant le résultat de la méthode Person.getName().

La question est :

Combien de fois la ligne 4 est-elle invoquée ?

① 1 fois ?
② 10 fois ?
③ Non Jérôme, elle n'est pas invoquée la ligne 4.
It depends!

spoiler
Vous êtes-vous dit qu’il y avait plusieurs bonnes réponses ?

La bonne réponse est:

It depends!

En réalité, la question était mal posée. La question, aurait du être :

"Est-ce que la méthode map est invoquée une fois, 10 fois, ainsi de suite ?" ou "Est-ce que la fonction qui est passée en paramètre de la méthode map est invoquée ?"

La méthode map, est bien appelée une seule fois, par contre, la fonction qui lui est passée en paramètre, elle, est bien invoquée 10 fois.

Il faut systématiquement différencier les méthodes de l’API Stream, qui ne font que de la configuration de pipeline, et les fonctions/predicats/... qu’on leur passe.

Quiz 2/3

Bon, ok, on a compris. À partir de maintenant, la question portera systématiquement sur le nombre d’invocations de la Function passée en paramètre de la méthode map.

1 public class Quizz {
2   public static void main(String[] args) {
3        getPeople()
4            .map(person -> person.getName());
5    }
6 }

La question est :

Combien de fois la ligne 4 est-elle invoquée ?
① 1 fois ?
② 10 fois ?
③ Non Jérôme, elle n'est pas invoquée la ligne 4.

spoiler

La bonne réponse est :

Non Jérôme, elle n’est pas invoquée la ligne 4.

Dans un stream, il y a deux types d’opérations :

  • Des opérations intermédiaires.
  • Des opérations finales.

Les opérations intermédiaires ne font que configurer un pipeline d’exécution, elles ne déclenchent rien. Tant qu’on n’a pas appelé une méthode finale sur un stream, il ne se passe rien du tout.

Quiz 3/3

1 public class Quiz {
2     public static void main(String[] args) {
3         getPeople()
4             .map(person -> person.getName())
5             .count();
6     }
7 }

La question est :

Combien de fois la ligne 4 est-elle invoquée ?
① 1 fois ?
② 10 fois ?
③ Non Jérôme, elle n'est pas invoquée la ligne 4.

spoiler

La bonne réponse est :

Non Jérôme, elle n’est pas invoquée la ligne 4.

Eeeeeeet oui, l’API stream est intelligente, et parmi les opérations terminales, il y en a certaines qui possèdent des shortcuts. Et c'est le cas de la méthode count qui est capable d’évaluer si toutes les opérations qui ont été exécutées avant elle peuvent avoir un impact sur la cardinalité de ce qu’il y a en sortie.

Ici, une seule opération map n’aura aucun impact sur la cardinalité, et donc, inutile de l’invoquer, ça n’a aucun intérêt. On n’a pas besoin de transformer des personnes en chaînes de caractères pour savoir qu’il y en à 10.

C'est assez important de comprendre que vous n'avez pas de garantie d'invocation. Et si, par exemple, vous faites partie de la team peek-