IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Tutoriel pour découvrir l’API Collections de Google Guava

La classe Iterables

Le but de cet article est l'exploration de la classe Iterables de l'API Collections de la bibliothèque Guava de Google. À noter que j'ai déjà publié un tutoriel traitant de la classe ImmutableList.

Comme exemple nous utiliserons un parc automobile, cela nous permettra de sonder de façon pratique et ludique les méthodes de cette classe.

En effet de par mon expérience, j'ai pu constater que certains développeurs (et parfois moi aussi) implémentaient des fonctionnalités alors que ces dernières étaient présentes dans des bibliothèques tierces.

Ainsi dans nos futurs projets respectons le vieil adage : "ne réinventez pas la roue".

Par ailleurs, je vous invite à créer un fil de discussion afin d’y laisser tous vos commentaires pour l’appréciation, voire pour l’amélioration des futurs tutoriels. Commentez Donner une note  l'article (5)

Article lu   fois.

L'auteur

Profil Pro

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Introduction

Dans ce troisième tutoriel sur l’exploration de la bibliothèque Guava de Google faisant suite au second tutoriel, nous découvrirons l’ensemble des méthodes statiques composant la classe utilitaire Iterables.

Par ailleurs comme il s'agit d'une découverte, je parcours la bibliothèque des méthodes de la classe Iterables en y greffant des exemples simples. Sans conteste la meilleure manière de découvrir une bibliothèque est de parcourir chacune de ses méthodes et de les implémenter les unes après les autres pour comprendre les subtilités de chacune. Ce tutoriel est avant tout pratique, mon fil conducteur est la page suivante https://github.com/google/guava/wiki/ImmutableCollectionsExplainedained traitant des Collections de l'API Google Guava. Le lecteur devra donc s’attendre à voir la mise en œuvre des méthodes de la classe ImmutableList de façon pragmatique et ludique. Souhaitons au lecteur d’apprécier toute la richesse de cette bibliothèque qui ne fait que s’améliorer au fur et à mesure des versions. Bonne lecture à tous.

II. Qu’est-ce que l’API Google Guava et pourquoi l’utiliser ?

L’API Google Guava est une bibliothèque contenant un ensemble de classes utilitaires fort utiles dans n’importe quel projet Java. En effet, cette API contient des classes allant du traitement des collections permettant de gérer des objets immuables, à la manipulation des chaînes de caractères, en passant par la gestion des entrées-sorties conversationnelles, et bien d’autres fonctionnalités qui facilitent la vie du développeur.

Dans cette série de tutoriels, nous n’aborderons que les classes utilitaires de l’API Collections. Cette dernière regroupe un ensemble de classes analogues à celles présentes dans le JDK, mais à la différence que ces dernières ont été améliorées par rapport à celles du JDK d’ORACLE.

En effet les développeurs de Google ont souhaité étendre les fonctionnalités des structures de données natives que nous utilisons au quotidien afin d’accroître notre productivité.

Le projet Guava représente le cœur du développement de Google, il représente des années de développement et une boîte à outils utilisée au quotidien par les développeurs de Google. Cette API est arrivée à maturité puisqu’elle est à l’heure actuelle à sa version 30.1 et ne cesse d’être agrémentée de nouvelles fonctionnalités.

Pour conclure cette section, nous dirons que dans ce second volet nous découvrirons l’ensemble des méthodes utilitaires statiques composant la classe utilitaire Iterables.

III. Ajouter Google Guava à votre projet

La bibliothèque Google Guava peut être ajoutée de plusieurs façons dans un projet. La façon la plus triviale est de récupérer le .jar depuis le site de Google, puis de placer ce dernier directement dans la bibliothèque de votre projet.

Une autre façon plus élégante est d’utiliser un outil industrialisé de build comme Apache Maven ou Gradle en y ajoutant la dépendance requise de Google Guava.

Installer Guava via Maven
Sélectionnez
1.
2.
3.
4.
5.
6.
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>30.1-jre</version>
</dependency>

IV. La classe utilitaire Iterables

Force est de constater que tout développeur familier avec le langage Java connaît l’utilité de pouvoir parcourir des implémentations (notamment List et Set) de manière uniforme sans devoir se soucier des mécanismes internes.

Google Guava est allé encore plus loin dans l’implémentation des fonctionnalités sous-jacentes à l’utilisation des objets itérables. Les développeurs de Google ont conçu de nombreuses méthodes utilitaires statiques permettant une gestion efficiente lorsque l’on travaille avec des objets sur lesquels on puisse itérer.

Mieux qu’un long discours dans le chapitre suivant, nous mettrons en œuvre la richesse de cette bibliothèque à travers un cas pratique de gestion d’un parc automobile.

V. Implémentation des méthodes de la classe Iterables

V-A. Les imports

Les imports
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import static java.lang.System.out;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.Queue;
import java.util.function.Function;
import java.util.function.Predicate;

V-B. Les attributs, les blocs et les méthodes statiques

Créons une classe Application qui contiendra les attributs, les blocs et les méthodes statiques pour la gestion de notre parc automobile.

Les attributs et blocs statiques
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
public final class Application {

    // constantes
    private final static int NB_MARQUES_VEHICULES = 5;
    private final static int NB_PEINTURES_VEHICULES = 5;
    private final static int NB_VEHICULES = 3;
    // predicates
    private final static Predicate<String> marquePeugeot;
    private final static Predicate<String> marqueOpel;
    private final static Predicate<String> marqueRenault;
    private final static Predicate<String> marqueMitsubishi;

    // structures de données
    private final static List<String> vehicules;
    private final static List<Number> consommations;
    private final static String[] peugeot;
    private final static String[] opel;
    private final static String[] peinture;

    static {
        peugeot = new String[NB_VEHICULES];
        peugeot[0] = "Peugeot Nouvelle SUV 3008";
        peugeot[1] = "Peugeot Nouvelle SUV 5008";
        peugeot[2] = "Peugeot Traveller/Expert Combi";

        opel = new String[NB_VEHICULES];
        opel[0] = "Opel Calibra";
        opel[1] = "Opel Ascona";
        opel[2] = "Opel Corsa";

        peinture = new String[NB_PEINTURES_VEHICULES];
        peinture[0] = "Gris Shark";
        peinture[1] = "Gris Thorium";
        peinture[2] = "Bourrasque";
        peinture[3] = "Bleu Encre";
        peinture[4] = "Noir Obsidien";

        vehicules = new ArrayList<>(NB_MARQUES_VEHICULES);
    }

    static { // la consommation du litre/100km
        final Byte deuxLitre100km = 2;
        final Short troisLitre100km = 3;
        consommations = new ArrayList<>();
        consommations.add(deuxLitre100km);
        consommations.add(troisLitre100km);
        consommations.add(4.3d); // Double
        consommations.add(5.8f); // Float
        consommations.add(6); // Integer
        consommations.add(7L); // Long
        consommations.add(8.5f); // Float
        consommations.add(9.2d); // Double
        consommations.add(9); // Integer
        consommations.add(9.7d); // Double
        consommations.add(10L); // Long
    }

    static { // predicates
        marquePeugeot = v -> v.contains("Peugeot");
        marqueOpel = v -> v.contains("Opel");
        marqueRenault = v -> v.contains("Renault");
        marqueMitsubishi = v -> v.contains("Mitsubishi");
    }

    static Iterable<String> iterableVehicules = new ArrayList<>(NB_MARQUES_VEHICULES);
    final static List<String> couleurs = Arrays.asList(new String[]{
        "Blanc Banquise", "Rouge Lucifer", "Gris Graphite", "Gris Futura", "Bleu de Sevres",
        "Noir Perla", "Gris Alluminium", "Rouge Aden", "Blanc Perle", "Bleu Lucia", "Gris Futura"});

    final static Iterable<String> iterableRenault
            = Arrays.asList(new String[]{"Renault Kangoo VP", "Renault Nouveau Grand Scenic", "Renault Alaskan"});
    final static Iterable<String> iterableCitroen
            = Arrays.asList(new String[]{"Citroen Nouvelle C-Elysée", "Citroen Nemo Multispace", "Citroen C4 Aircross"});
    final static Iterable<String> iterableToyota
            = Arrays.asList(new String[]{"Toyota Auris", "Toyota Nouvelle Yaris", "Toyota Aygo X "});

    final static Iterable<Integer> iterableDiametreJantes = Arrays.asList(new Integer[]{13, 14, 15, 16, 17, 18});

    public static void main(String[] args) {
        // commençons par afficher les véhicules de la marque peugeot
        out.println(Arrays.asList(peugeot)); // [Peugeot Nouvelle SUV 3008, Peugeot Nouvelle SUV 5008, Peugeot Traveller/Expert Combi]
    }
}

V-C. La méthode addAll

Ajoutons l’ensemble de nos véhicules de la marque Peugeot dans notre collection de véhicules. La méthode addAll(Collection<T> addTo, Iterable<? extends T> elementsToAdd) nous permet d’effectuer cette action avec une valeur booléenne à true si la collection a été modifiée à l’issue de cette opération.

Méthode addAll(Collection<T> addTo, Iterable<? extends T> elementsToAdd)
Sélectionnez
1.
2.
final boolean addAllVehicules = Iterables.addAll(vehicules, Arrays.asList(peugeot));
out.println(addAllVehicules); // true

V-D. La méthode all

Nous aurions pu également ajouter à notre collection de véhicules uniquement les véhicules de la marque Peugeot. Admettons que ces derniers soient présents dans un ensemble de marques de véhicules distinctes. Pour cela la méthode all(Iterable<T> iterable, Predicate<? super T> predicate) est préférable, car elle prend comme second paramètre un Predicate. Si tous les éléments de la collection répondent à la condition du Predicate, alors la valeur booléenne true est restituée sinon false dans le cas contraire.

Méthode all(Iterable<T> iterable, Predicate<? super T> predicate)
Sélectionnez
1.
2.
3.
4.
5.
6.
// Attention : il s'agit du Predicate de Google Guava et pas celui du JDK !!!
// Predicate where a com.google.common.base.Predicate is expected, use the method reference predicate::test.
final boolean allMarquePeugeot = Iterables.all(vehicules, marquePeugeot::test);
out.println(allMarquePeugeot); // true
vehicules.add("Opel Calibra"); // on ajoute un véhicule qui n'est pas de la marque Peugeot
out.println(Iterables.all(vehicules, marquePeugeot::test)); // false

V-E. La méthode any

Maintenant, soyons moins restrictifs en recherchant dans notre collection de véhicules n’importe quel élément répondant à une condition bien précise. Pour cela la méthode any(Iterable<T> iterable, Predicate<? super T> predicate) nous permet d’effectuer cette action. Cette méthode renvoie la valeur true en cas de succès ou false dans le cas contraire.

Méthode any(Iterable<T> iterable, Predicate<? super T> predicate)
Sélectionnez
1.
2.
out.println(Iterables.any(vehicules, marqueOpel::test)); // true puisque nous avons ajouté précédemment un véhicule de la marque Opeml
out.println(Iterables.any(vehicules, marqueRenault::test)); // false car on n'a pas ajouté de vehicule de la marque Renault

V-F. La méthode concat

Nous décidons tout compte fait de concaténer la liste de tous nos véhicules dans un Iterable. Pour cela le polymorphisme de la méthode concat() met à notre disposition un panel de possibilités.

Méthode concat(Iterable<? extends T> a, Iterable<? extends T> b, Iterable<? extends T> c, Iterable<? extends T> d)
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
iterableVehicules = Iterables.concat(iterableRenault);
out.println(iterableVehicules);
iterableVehicules = Iterables.concat(iterableRenault, iterableCitroen);
out.println(iterableVehicules);
iterableVehicules = Iterables.concat(iterableRenault, iterableCitroen, iterableToyota);
out.println(iterableVehicules);
iterableVehicules = Iterables.concat(iterableRenault, iterableCitroen, iterableToyota, Arrays.asList(opel));
out.println(iterableVehicules);
/*
[Renault Kangoo VP, Renault Nouveau Grand Scenic, Renault Alaskan]
[Renault Kangoo VP, Renault Nouveau Grand Scenic, Renault Alaskan, Citroen Nouvelle C-Elysée, Citroen Nemo Multispace, Citroen C4 Aircross]
[Renault Kangoo VP, Renault Nouveau Grand Scenic, Renault Alaskan, Citroen Nouvelle C-Elysée, Citroen Nemo Multispace, Citroen C4 Aircross, Toyota Auris, Toyota Nouvelle Yaris, Toyota Aygo X ]
[Renault Kangoo VP, Renault Nouveau Grand Scenic, Renault Alaskan, Citroen Nouvelle C-Elysée, Citroen Nemo Multispace, Citroen C4 Aircross, Toyota Auris, Toyota Nouvelle Yaris, Toyota Aygo X , Opel Calibra, Opel Ascona, Opel Corsa]
*/

V-G. La méthode consumingIterable

Nous voulons renvoyer les codes couleurs de nos véhicules sous la forme d’une vue parcourue par un objet de type Iterator. La méthode consumingIterable(Iterable<T> iterable) nous permet d’effectuer cette opération.

Méthode Iterable<T> consumingIterable(Iterable<T> iterable)
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
final Queue<String> queueCodesCouleurs = new LinkedList<>(couleurs);
final Iterator<String> iterator = Iterables.consumingIterable(queueCodesCouleurs).iterator();
int index = 0;
while (iterator.hasNext() && index <= 5) { // on ne veut afficher que les 5 premières couleurs
    final String couleur = iterator.next();
    out.println(couleur);
    index++;
}
/*
Blanc Banquise
Rouge Lucifer
Gris Graphite
Gris Futura
Bleu de Sevres
Noir Perla
*/

V-H. La méthode contains

Nous désirons savoir si la couleur « Rouge Aden » est présente dans notre Iterable des couleurs. La méthode contains(Iterable<?> iterable, @Nullable Object element) renvoie la valeur true en cas de succès ou false dans le cas contraire.

Méthode contains(Iterable<?> iterable, @Nullable Object element)
Sélectionnez
1.
2.
final boolean containsRougeAden = Iterables.contains(couleurs, "Rouge Aden");
out.println(containsRougeAden); // true

V-I. La méthode cycle

V-I-1. cycle(Iterable<T> iterable)

Nous pouvons également effectuer le parcours de nos codes couleurs en utilisant la méthode cycle(Iterable<T> iterable). Cependant si vous utilisez cette méthode dans une boucle, vous devrez explicitement ajouter le mot-clé break sinon le résultat produira une boucle infinie.

Méthode cycle(Iterable<T> iterable)
Sélectionnez
1.
2.
3.
final Iterable<String> iterableCouleurs = Iterables.cycle(couleurs);
out.println(iterableCouleurs);
// [Blanc Banquise, Rouge Lucifer, Gris Graphite, Gris Futura, Bleu de Sevres, Noir Perla, Gris Alluminium, Rouge Aden, Blanc Perle, Bleu Lucia, Gris Futura] (cycled)

V-I-2. cycle(T… elements)

Une autre signature de cette méthode prend comme paramètre une ellipse qui nous permet d’ajouter un Iterable de carburants.

Méthode cycle(T... elements)
Sélectionnez
1.
2.
3.
final Iterable<String> iterableCarburant = Iterables.cycle("Electric", "Diesel", "GNV", "Hybride");
out.println(iterableCarburant);
//[Electric, Diesel, GNV, Hybride] (cycled)

V-J. La méthode elementsEqual

Nous pouvons aussi comparer deux objets Iterables afin de savoir s'ils sont identiques. Pour cela nous utilisons la méthode elementsEqual(Iterable<?> iterable1, Iterable<?> iterable2). Cette méthode renvoie true en cas de succès ou false dans le cas contraire.

Méthode Iterable<?> iterable1, Iterable<?> iterable2
Sélectionnez
1.
2.
3.
4.
final Iterable<String> iterableCarburantEssence = ImmutableList.of("Essence");
final Iterable<String> iterableCarburantEssenceSP = ImmutableList.of("Essence", "Essence Sans Plomb 95", "Essence Sans Plomb 98");
final boolean elementsEqualCarburantsEssenceSP = Iterables.elementsEqual(iterableCarburantEssence, iterableCarburantEssenceSP);
out.println(elementsEqualCarburantsEssenceSP); // false

V-K. La méthode filter

V-K-1. filter(Iterable<?> unfiltered, Class<T> desiredType)

Nous souhaitons positionner un filtre pour récupérer uniquement les consommations de carburants de type Float. La méthode filter(Iterable<?> unfiltered, Class<T> desiredType) permet d’effectuer cette opération.

Méthode (Iterable<?> unfiltered, Class<T> desiredType)
Sélectionnez
1.
2.
final Iterable<Float> consomationsFilteredByDesiredType = Iterables.filter(consommations, Float.class);        
out.println(consomationsFilteredByDesiredType); // [5.8, 8.5]

V-K-2. filter(Iterable<T> unfiltered, Predicate<? super T> retainIfTrue)

Cette méthode dans une autre version prend un prédicat comme second paramètre. Ainsi nous pouvons récupérer uniquement les véhicules de la marque Renault si ces derniers sont présents dans notre Iterable de véhicules.

Méthode filter(Iterable<T> unfiltered, Predicate<? super T> retainIfTrue)
Sélectionnez
1.
2.
3.
final Iterable<String> consommationsFilteredByPredicate = Iterables.filter(iterableVehicules, marqueRenault::test);
out.println(consommationsFilteredByPredicate); // [Renault Kangoo VP, Renault Nouveau Grand Scenic, Renault Alaskan]
// si le test du predicate est false alors la méthode filter renvoie []. Exemple: marquePeugeot::test

V-L. La méthode find

V-L-1. find(Iterable<? extends T> iterable, Predicate<? super T> predicate, T defaultValue)

Nous pouvons rechercher un véhicule dans notre Iterable de véhicules à l’aide d’un prédicat. Néanmoins, si ce dernier n’est pas présent, il serait pertinent d’en récupérer un par défaut. Par contre cette méthode renverra directement le premier élément correspondant au prédicat… et n’ira pas plus loin dans sa recherche.

find(Iterable<? extends T> iterable, Predicate<? super T> predicate, T defaultValue)
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
// on crée un iterable de la marque Peugeot
final Iterable<String> iterablePeugeot = Iterables.concat(Arrays.asList(peugeot));
final String defaultValue = "Peugeot 308 CC";
final String findWithPredicateOrDefaultValue = Iterables.find(iterablePeugeot, marquePeugeot::test, defaultValue);
// la marque Renault n'étant pas ajoutée à notre iterableVehicules, la valeur par défaut est renvoyée
//String findWithPredicateOrDafaultValue = Iterables.find(iterableVehicules, marqueRenault::test, defaultValue);
out.println(findWithPredicateOrDefaultValue);
// Peugeot Nouvelle SUV 3008

V-L-2. find(Iterable<T> unfiltered, Predicate<? super T> retainIfTrue)

Idem que précédemment, mais sans valeur par défaut si le test du prédicat renvoie false.

Méthode find(Iterable<T> unfiltered, Predicate<? super T> retainIfTrue)
Sélectionnez
1.
2.
final String findWithPredicate = Iterables.find(iterablePeugeot, marquePeugeot::test);
out.println(findWithPredicate); // Peugeot Nouvelle SUV 3008

V-M. La méthode frequency

Recherchons le nombre d’occurrences d’un code couleurs dans notre Iterable de couleurs. La méthode frequency(Iterable<?> iterable, @Nullable Object element) permet d’effectuer cette opération.

Méthode frequency(Iterable<?> iterable, @Nullable Object element)
Sélectionnez
1.
2.
3.
4.
final int frequencyCouleurs = Iterables.frequency(couleurs, "Gris Futura");
out.println(frequencyCouleurs); // 2
//final long frequencyCouleursStream = couleurs.stream().filter(Predicate.isEqual("Gris Futura")).count();
//out.println(frequencyCouleursStream); // 2

V-N. La méthode get

V-N-1. get(Iterable<? extends T> iterable, int position, T defaultValue)

Nous pouvons récupérer un véhicule dans notre Iterable de véhicules en mentionnant une position spécifique dans l’Iterable. Cependant si ce dernier n’est pas présent, il serait pertinent d’en récupérer un par défaut.

Méthode get(Iterable<? extends T> iterable, int position, T defaultValue)
Sélectionnez
1.
2.
3.
4.
//final String getCouleurOrDefaultValue = Iterables.get(iterableVehicules, 3, defaultValue);
//out.println(getCouleurOrDefaultValue); // Citroen Nouvelle C-Elysée
final String getCouleurOrDefaultValue = Iterables.get(iterableVehicules, 14, defaultValue);
out.println(getCouleurOrDefaultValue); // Peugeot 308 CC

V-N-2. get(Iterable<T> iterable, int position)

Idem que précédemment, mais cette fois-ci sans valeur par défaut. L’index de la position spécifié doit exister !

Méthode get(Iterable<T> iterable, int position)
Sélectionnez
1.
2.
final String getVehiculeToyota = Iterables.get(iterableToyota, 2); // Toyota Aygo X
out.println(getVehiculeToyota);

V-O. La méthode getFirst

Nous voulons cette fois-ci récupérer le premier véhicule présent dans notre Iterable de véhicules de la marque Peugeot. La méthode getFirst(Iterable<? extends T> iterable, T defaultValue) sera utilisée pour cette action. À noter qu’ici aussi si le véhicule ne peut être récupéré une valeur par défaut sera restituée.

Méthode getFirst(Iterable<? extends T> iterable, T defaultValue)
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
final String getFirstVehiculePeugeot = Iterables.getFirst(iterablePeugeot, defaultValue);
out.println(getFirstVehiculePeugeot);
// on instancie un nouvel iterable de véhicules de la marque Volkswagen
Iterable<String> iterableVolkswagen = new ArrayList<>(NB_MARQUES_VEHICULES);
// on n'ajoute aucun véhicule à cette liste, on la laisse vide
final String defaultVolkswagen = "Volkswagen Passat"; // le véhicule Volkswagen par défaut
final String getFirstVehiculeVolkswagen = Iterables.getFirst(iterableVolkswagen, defaultVolkswagen);
out.println(getFirstVehiculeVolkswagen);

V-P. La méthode getLast

V-P-1. getLast(Iterable<? extends T> iterable, T defaultValue)

Nous voulons cette fois-ci récupérer le dernier véhicule présent dans notre Iterable de véhicules de la marque Peugeot. Par contre si l’Iterable est vide une valeur par défaut est renvoyée.

Méthode getLast(Iterable<? extends T> iterable, T defaultValue)
Sélectionnez
1.
2.
final String getLastVehiculePeugeot = Iterables.getLast(iterablePeugeot, defaultValue);
out.println(getLastVehiculePeugeot);

V-P-2. getLast(Iterable<T> iterable)

Idem que précédemment, mais cette fois-ci si l’Iterable est vide une exception java.util.NoSuchElementException est renvoyée.

Méthode getLast(Iterable<T> iterable)
Sélectionnez
1.
2.
final String getLastVehicule = Iterables.getLast(iterableVehicules);
out.println(getLastVehicule); // Opel Corsa

V-Q. La méthode getOnlyElement

V-Q-1. getOnlyElement((Iterable<? extends T> iterable, T defaultValue)

Maintenant nous souhaitons récupérer un unique élément de notre Iterable en restituant toutefois une valeur par défaut si on ne parvient pas à récupérer cet élément.

Méthode getOnlyElement(Iterable<? extends T> iterable, T defaultValue)
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
final List<String> iterableMitsubishi = new ArrayList<>(NB_MARQUES_VEHICULES);
iterableMitsubishi.add("Mitsubishi Outlander PHEV"); // iterableMitsubishi contient un élément
final String defaultMitsubishi = "Mitsubishi ASX"; // le véhicule par défaut de la marque Mitsubishi
final String getOnlyElementVehiculeMitsubishiWithoutDefaultValue = Iterables.getOnlyElement(iterableMitsubishi, defaultMitsubishi);
// le véhicule ajouté sera affiché et pas celui par défaut
out.println(getOnlyElementVehiculeMitsubishiWithoutDefaultValue); // Mitsubishi Outlander PHEV
iterableMitsubishi.clear(); // on nettoie le contenu de iterableMitsubishi donc il n'y a plus aucun véhicule
final String getOnlyElementVehiculeMitsubishiWithDefaultValue = Iterables.getOnlyElement(iterableMitsubishi, defaultMitsubishi);       out.println(getOnlyElementVehiculeMitsubishiWithDefaultValue); // Mitsubishi ASX

V-Q-2. getOnlyElement(Iterable<T> iterable)

Idem que précédemment, mais sans restitution d’une valeur par défaut si l’élément n’est pas récupéré.

Méthode getOnlyElement(Iterable<T> iterable)
Sélectionnez
1.
2.
3.
iterableMitsubishi.add("Mitsubishi Outlander"); // on ajoute un véhicule à iterableMitsubishi
final String getOnlyElementVehiculeMitsubishi = Iterables.getOnlyElement(iterableMitsubishi);
out.println(getOnlyElementVehiculeMitsubishi); // Mitsubishi Outlander

V-R. La méthode indexOf(Iterable<T> iterable, Predicate<? super T> predicate)

Si nous souhaitons récupérer l’indice de la position du premier élément vérifiant un prédicat, la méthode indexOf(Iterable<T> iterable, Predicate<? super T> predicate) permet d’effectuer cette opération. Nous voulons savoir à quelle position se trouve le premier véhicule de la marque Opel dans notre Iterable de véhicules. À noter que cette méthode renvoie -1 si l’élément n’est pas présent dans l’Iterable.

Méthode indexOf(Iterable<T> iterable, Predicate<? super T> predicate)
Sélectionnez
1.
2.
3.
4.
final int indexOfVehiculeWithPredicate = Iterables.indexOf(iterableVehicules, marqueOpel::test);
out.println(indexOfVehiculeWithPredicate); // 9
final int indexOfVoitureWithPredicate = Iterables.indexOf(iterableVehicules, marqueMitsubishi::test);
out.println(indexOfVoitureWithPredicate); // -1

V-S. La méthode isEmpty

Nous pouvons également vérifier si notre Iterable est vide en utilisant la méthode isEmpty(Iterable<?> iterable).

Méthode isEmpty(Iterable<?> iterable)
Sélectionnez
1.
2.
3.
4.
final boolean isEmptyVehiculeToyota = Iterables.isEmpty(iterableToyota); // !vehicules.stream().findAny().isPresent();
out.println(isEmptyVehiculeToyota); // false
final boolean isEmptyVehiculeVolkswagen = Iterables.isEmpty(iterableVolkswagen);
out.println(isEmptyVehiculeVolkswagen); // true

V-T. La méthode limit

Par ailleurs il est aussi possible de limiter la taille de notre Iterable. La méthode limit(Iterable<T> iterable, int limitSize) permet d’effectuer cette opération. Nous ne voulons désormais que quatre types de carburants.

Méthode limit((Iterable<T> iterable, int limitSize)
Sélectionnez
1.
2.
final Iterable<String> limitTypeCarburants = Iterables.limit(iterableCarburant, 4);
out.println(limitTypeCarburants); // [Electric, Diesel, GNV, Hybride]

V-U. La méthode mergeSorted

Nous souhaitons désormais avoir un tri sur la longueur du nom des véhicules de deux Iterables. La méthode mergeSorted(Iterable<? extends Iterable<? extends T>> iterables, Comparator<? super T> comparator) permet d’effectuer cette opération.

Méthode (Iterable<? extends Iterable<? extends T>> iterables, Comparator<? super T> comparator)
Sélectionnez
1.
2.
3.
4.
5.
6.
// on ajoute le véhicule Volkwagen par défaut dans notre iterableVolkswagen
iterableVolkswagen = Arrays.asList(new String[]{defaultVolkswagen});
// nous voulons effectuer un tri en fonction de la longueur du nom du véhicule du plus long au plus court
final Comparator<String> comparator = (String o1, String o2) -> (o2.length() - o1.length());
final Iterable<String> mergedSortedWithComparator = Iterables.mergeSorted(ImmutableList.of(iterableMitsubishi, iterableVolkswagen), comparator);
out.println(mergedSortedWithComparator); // [Mitsubishi Outlander, Volkswagen Passat]

V-V. La méthode paddedPartition

Nous pouvons également diviser notre Iterable en sous-listes immuables d’une longueur définie en remplissant la dernière liste de l’Iterable avec des valeurs nulles si nécessaire.

Méthode paddedPartition(Iterable<T> iterable, int size)
Sélectionnez
1.
2.
final Iterable<List<String>> paddedPartitionVehicules = Iterables.paddedPartition(iterableVehicules, NB_VEHICULES); 
out.println(paddedPartitionVehicules); // [[Renault Kangoo VP, Renault Nouveau Grand Scenic, Renault Alaskan], [Citroen Nouvelle C-Elysée, Citroen Nemo Multispace, Citroen C4 Aircross], [Toyota Auris, Toyota Nouvelle Yaris, Toyota Aygo X ], [Opel Calibra, Opel Ascona, Opel Corsa]]

V-W. La méthode partition

La méthode partition(Iterable<T> iterable, int size) effectue la même action que la méthode précédente par contre l’Iterable final peut être d’une longueur plus petite que la taille définie en second paramètre de la méthode.

Méthode partition(Iterable<T> iterable, int size)
Sélectionnez
1.
2.
final Iterable<List<String>> partitionVehicules = Iterables.partition(iterableVehicules, 5);
out.println(partitionVehicules); // [[Renault Kangoo VP, Renault Nouveau Grand Scenic, Renault Alaskan, Citroen Nouvelle C-Elysée, Citroen Nemo Multispace], [Citroen C4 Aircross, Toyota Auris, Toyota Nouvelle Yaris, Toyota Aygo X , Opel Calibra], [Opel Ascona, Opel Corsa]]

V-X. La méthode removeAll

Certains coloris ne sont plus disponibles dans notre palette de couleurs des véhicules ; nous souhaitons donc les supprimer. La méthode removeAll(Iterable<?> removeFrom, Collection<?> elementsToRemove) renverra la valeur booléenne true si l’opération de suppression a pu s’effectuer.

Méthode removeAll(Iterable<?> removeFrom, Collection<?> elementsToRemove)
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
final List<String> iterablePaletteCouleurs = new ArrayList<>(peinture.length);
iterablePaletteCouleurs.addAll(Arrays.asList(peinture));
final Collection<String> couleursToRemove = new ArrayList<>();
couleursToRemove.add("Bourrasque");
couleursToRemove.add("Rouge Lucifer");
out.println(iterablePaletteCouleurs); // [Gris Shark, Gris Thorium, Bourrasque, Bleu Encre, Noir Obsidien]
final boolean removeAllCouleurs = Iterables.removeAll(iterablePaletteCouleurs, couleursToRemove);
out.println(removeAllCouleurs); // true

V-Y. La méthode removeIf

Il est également possible de supprimer des éléments en fonction d’un prédicat défini. Nous souhaitons supprimer les véhicules de la marque Renault sachant que notre Collection ne contient pas de véhicules de la marque Renault. Ensuite nous tenterons de supprimer les véhicules de la marque Opel.

Par contre en utilisant Java 8, si vous utilisez une Collection (comme une ArrayList<T>) il est préférable d’utiliser removeFrom.removeIf(predicate) où removeFrom est la Collection et removeIf la méthode avec le prédicat en paramètre.

Méthode removeIf(Iterable<T> removeFrom, Predicate<? super T> predicate)
Sélectionnez
1.
2.
3.
4.
5.
6.
// Java 8 users: if removeFrom is a Collection, use removeFrom.removeIf(predicate) instead.         
out.println(vehicules);
final boolean removeIfFoundMarqueRenault = vehicules.removeIf(marqueRenault::test);
out.println(removeIfFoundMarqueRenault); // false
final boolean removeIfFoundMarqueOpel = vehicules.removeIf(marqueOpel::test);
out.println(removeIfFoundMarqueOpel); // true

V-Z. La méthode retainAll

Certains coloris sont plus attrayants et nous voulons les retenir dans notre sélection de palette de couleurs. La méthode retainAll(Iterable<?> removeFrom, Collection<?> elementsToRetain) renverra la valeur true si l’on a pu retenir les éléments sélectionnés.

Méthode retainAll(Iterable<?> removeFrom, Collection<?> elementsToRetain)
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
final Collection<String> couleursToRetain = new ArrayList<>();
// on ajoute deux nouveaux coloris 
couleursToRetain.add("Bleu Californium");
couleursToRetain.add("Gris Baryum");
// ... que l'on souhaite retenir pour la nouvelle collection
iterablePaletteCouleurs.add("Bleu Californium");
iterablePaletteCouleurs.add("Gris Baryum");
out.println(iterablePaletteCouleurs); // [Gris Shark, Gris Thorium, Bleu Encre, Noir Obsidien, Bleu Californium, Gris Baryum]
final boolean retainAllPeinture = Iterables.retainAll(iterablePaletteCouleurs, couleursToRetain);
out.println(retainAllPeinture); // true car on a pu retenir nos coloris sélectionnés
out.println(iterablePaletteCouleurs); // [Bleu Californium, Gris Baryum]

V-AA. La méthode size

Nous voulons récupérer le nombre d’éléments présents dans un Iterable ; en quelque sorte sa longueur. La méthode size(Iterable<?> iterable) permet d’effectuer cette action.

size(Iterable<?> iterable)
Sélectionnez
1.
2.
final int nombreVehicules = Iterables.size(iterableVehicules);
out.println(nombreVehicules); // 12

V-AB. La méthode skip

Nous souhaitons effectuer un filtre sur notre gamme de véhicules en récupérant uniquement les véhicules qui sont au-delà du 3e véhicule. La méthode skip(Iterable<T> iterable, int numberToSkip) permet d’effectuer cette action.

Méthode skip(Iterable<T> iterable, int numberToSkip)
Sélectionnez
1.
2.
3.
final Iterable<String> skipVehicules = Iterables.skip(iterableVehicules, NB_VEHICULES);
// on ne veut pas les 3 premiers véhicules, mais uniquement les 9 autres
out.println(skipVehicules); // [Citroen Nouvelle C-Elysée, Citroen Nemo Multispace, Citroen C4 Aircross, Toyota Auris, Toyota Nouvelle Yaris, Toyota Aygo X , Opel Calibra, Opel Ascona, Opel Corsa]

V-AC. La méthode toArray

Si nous souhaitons copier notre Iterable dans un tableau, nous pouvons utiliser la méthode toArray(Iterable<? extends T> iterable, Class<T> type).

Méthode toArray(Iterable<? extends T> iterable, Class<T> type)
Sélectionnez
1.
2.
final String[] toArrayVehicules = Iterables.toArray(iterableVehicules, String.class);
out.println(Arrays.toString(toArrayVehicules)); // [Renault Kangoo VP, Renault Nouveau Grand Scenic, Renault Alaskan, Citroen Nouvelle C-Elysée, Citroen Nemo Multispace, Citroen C4 Aircross, Toyota Auris, Toyota Nouvelle Yaris, Toyota Aygo X , Opel Calibra, Opel Ascona, Opel Corsa]

V-AD. La méthode toString

À l’instar de la méthode toString du JDK d’Oracle, la méthode toString(Iterable<?> iterable) de la classe Iterables permet de mettre sous forme d’une chaîne de caractères un objet Iterable.

Méthode toString(Iterable<?> iterable)
Sélectionnez
1.
out.println(Iterables.toString(iterableToyota)); // [Toyota Auris, Toyota Nouvelle Yaris, Toyota Aygo X ]

V-AE. La méthode transform

Nous souhaitons désormais augmenter le diamètre des jantes de nos véhicules. La méthode transform(Iterable<F> fromIterable, Function<? super F,? extends T> function) permet d’effectuer cette opération.

Méthode transform(Iterable<F> fromIterable, Function<? super F,? extends T> function)
Sélectionnez
1.
2.
3.
4.
// on décide d'augmenter le diamètre des jantes des véhicules 
final Function<Integer, Float> multiplier = t -> t * 1.14f;
final Iterable<Float> augmenterDiametreJantes = Iterables.transform(iterableDiametreJantes, multiplier::apply);
out.println(augmenterDiametreJantes); // [14.82, 15.96, 17.1, 18.24, 19.38, 20.52]

V-AF. La méthode tryFind

Dans notre Iterable de véhicules, nous souhaitons trouver des voitures de la marque Renault. Nous pouvons utiliser la méthode tryFind((Iterable<T> iterable, Predicate<? super T> predicate) en lui appliquant un prédicat.

À noter que cette méthode renvoie un objet de type Optional, car le résultat de la recherche est « optionnel ». On essaye de trouver un élément sans être sûr de pouvoir le trouver.

Méthode tryFind(Iterable<T> iterable, Predicate<? super T> predicate)
Sélectionnez
1.
2.
3.
4.
out.println(iterableVehicules);
// équivaut à vehicules.stream().filter(marqueRenault::test).findFirst() donc renvoie le premier élément trouvé
final Optional<String> tryFindMarqueRenault = Iterables.tryFind(iterableVehicules, marqueRenault::test).toJavaUtil();
out.println(tryFindMarqueRenault); // [Renault Kangoo VP, Renault Nouveau Grand Scenic, Renault Alaskan, Citroen Nouvelle C-Elysée, Citroen Nemo Multispace, Citroen C4 Aircross, Toyota Auris, Toyota Nouvelle Yaris, Toyota Aygo X , Opel Calibra, Opel Ascona, Opel Corsa]

V-AG. La méthode unmodifiableIterable

Nous pouvons également rendre immuable notre Iterable en utilisant la méthode unmodifiableIterable(Iterable<? extends T> iterable).

Méthode unmodifiableIterable(Iterable<? extends T> iterable)
Sélectionnez
1.
2.
final Iterable<String> unmodifiableIterableVehicules = Iterables.unmodifiableIterable(iterableCarburantEssenceSP);
out.println(unmodifiableIterableVehicules); // [Essence, Essence Sans Plomb 95, Essence Sans Plomb 98]

VI. Conclusion

Nous avons fait le tour des méthodes utilitaires présentes dans la classe Iterables. Comme vous avez pu le constater, ces méthodes sont à la fois très simples d’utilisation et particulièrement efficaces. Je vous invite fortement à les implémenter dans vos projets, car elles vous apporteront des avantages sans précédent en termes de productivité.

Par ailleurs, je vous invite comme d’habitude à créer un fil de discussion afin d’y laisser tous vos commentaires pour l’appréciation, voire pour l’amélioration des futurs tutoriels.

VII. Remerciements

Je remercie claudeLELOUP pour la relecture orthographique de cet article, la communauté developpez.com qui propose un forum d’entraide d’une richesse fortement appréciable, Mickael Baron qui donne de son temps pour s’occuper de la rubrique Java, et surtout RomeoBeni pour l’écriture d’un ouvrage d’une rare simplicité dans l’apprentissage de la programmation en Java.

Pour finir merci encore à tous les membres répondant aux questions des débutants en programmation. Un grand merci à tous.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2021 Rony Rauzduel. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.