Copy of https://perso.isima.fr/loic/java/exo_jse_base_stream.php
tete du loic

 Loïc YON [KIUX]

  • Enseignant-chercheur
  • Référent Formation Continue
  • Responsable des contrats pros ingénieur
  • Référent entrepreneuriat
  • Responsable de la filière F2 ingénieur
  • Secouriste Sauveteur du Travail
mail
loic.yon@isima.fr
phone
(+33 / 0) 4 73 40 50 42
location_on
Institut d'informatique ISIMA
  • twitter
  • linkedin
  • viadeo

[JavaSE] Streams

 Cette page commence à dater. Son contenu n'est peut-être plus à jour. Contactez-moi si c'est le cas!

Date de première publication : 2023/02/06

Notions : manipuluation des collections et streams

Exemples du cours

Voici comment créer une liste avec deux manières de l'afficher :


List list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

// une liste est directement affichable
System.out.println(list);

// on peut appliquer une opération terminale
// l'action est donnée par une référence de méthode
list.stream().forEach(System.out::println);


// Creation d'un stream d'entiers :
IntStream.rangeClosed(1, 10);

// ou encore
Stream stream = Stream.iterate(1, n -> n + 1).limit(10);

Dans le dernier exemple, on convertit la liste en stream. On peut également faire l'inverse si nécessaire, on peut créer une liste à partir d'un stream (bon, là, y a pas d'intérêt, on a déjà la liste):


List l = list.stream().collect(Collectors.toList()); 
System.out.println(l);

On va maintenant trier les nombres pairs de plusieurs manières :


// avec une lambda
list.stream().filter(n -> n % 2 == 0);

// avec une inferface fonctionnelle
list.stream().filter(new Predicate() {
                    public boolean test(Integer i) {
                        return Integer.valueOf(i) % 2 == 0;
                    }
                });
et la dernière en montrant l'interface fonctionnelle :

class Rien {
    static public boolean isEven(Integer i) {
        return Integer.valueOf(i) % 2 == 0;
    }
}

list.stream().filter(Rien::isOdd);

Il n'est même pas nécessaire de préciser l'interface même si c'est une bonne pratique !

Dans le dernier exemple isEven() est une méthode de classe, donc la référence de méthode est donnée par rapport à la classe. Si la méthode est une méthode classique, il faut la lier à une instance instance::methode.

Application : exploitation de données

Nous allons reprendre l'exemple classique de la liste de créateurs de langages de programmation. Par exemple :


gosling:james:java:1995
stroustrup:bjarne:c++:1983
van rossum:guido:1991
hoare:graydon:rust:2006

Ces données peuvent être stockées dans des objets de type Personne qui dispose des différents attributs nécessaires.

On veut faire différentes opérations sur les données :

La dernière chose que l'on va faire est de calculer l'année moyenne de création d'un langage. Vous pourrez à cet effet utiliser mapToInt() pour transformer le stream objet en IntStream puis appliquer des méthodes comme average(), sum(), count()

Lecture des données avec un Stream

On peut lire le fichier texte avec des méthodes "classiques" mais on peut également le faire avec un Stream


Stream<String> stream = Files.lines(Paths.get(nomDuFichier));
stream.forEach(System.out::println);

dans un try-with-resources ou un try-catch standard.

Le code fourni permet de lire un stream de chaines de caractères mais il est possible de créer un stream de Personne

Pour ce faire, il est possible d'associer une chaine de caractères et une personne avec map, ou bien encore d'analyser la chaine de caractères et de créer ensuite une personne :

La classe String peut être remplacée par la classe Personne et le stream transformé en collection grâce à la méthode collect() pour éviter les lectures multiples.


// methode 1
stream.map(ligne -> ligne.split(":")).map(tableau -> new Personne(tableau[0], tableau[1], tableau[2], tableau[3]));

// methode 2
stream.map(ligne -> new Personne(ligne));

Vous choisirez une méthode et écrirez le constructeur qui va bien. Vous aurez également à définir la méthode toString() pour avoir un affichage correct.

Exploitations des données

Pour ce faire, on vous propose d'utiliser un Stream et de donner de différentes manières le "comparateur". Pour rappel, voici quelques possibilités vues en cours :

La dernière chose que l'on va faire est de calculer l'année moyenne de création d'un langage.

Vous pourrez à cet effet utiliser :

  1. mapToInt() pour transformer le stream objet en IntStream puis appliquer des méthodes comme average(), sum(), count()
  2. Un collector particulier et ensuite disposer de méthodes : averagingInt(), summingInt() ou encore summarizingInt(). Le collecteur permet aussi de regroupe les éléments si besoin avec groupBy