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

La classe Iterables

Rony Rauzduel

L'objectif de ce troisième article sur l’exploration de la bibliothèque Guava de Google est de vous présenter les méthodes statiques composant la classe utilitaire Iterables.

Cet article nous permettra d’apprécier toute la richesse de cette bibliothèque qui ne fait que s’améliorer au fur et à mesure des versions.

Lors de l’écriture de cet article, nous avons utilisé la version 30.1.1 de Google Guava.

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.

Vous pouvez également consulter mes précédents tutoriels pour découvrir la bibliothèque Guava.

La classe Lists

La classe ImmutableList

Pour réagir au contenu de cet article, un espace de dialogue vous est proposé sur le forum. Commentez

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

- Auteur : Rony Rauzduel

- Parution : 6 octobre 2021

- Mise à jour : 3 novembre 2021

- Public visé :

- Licence : 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 et 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.

Sommaire

- I. Introduction

- II. Ajouter Google Guava à votre projet (Rappel)

- III. La classe utilitaire Iterables

- IV. Implémentation des méthodes de la classe Iterables

- IV-A. Les imports

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

- IV-C. La méthode addAll

- IV-D. La méthode all

- IV-E. La méthode any

- IV-F. La méthode concat

- IV-G. La méthode consumingIterable

- IV-H. La méthode contains

- IV-I. La méthode cycle

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

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

- IV-J. La méthode elementsEqual

- IV-K. La méthode filter

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

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

- IV-L. La méthode find

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

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

- IV-M. La méthode frequency

- IV-N. La méthode get

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

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

- IV-O. La méthode getFirst

- IV-P. La méthode getLast

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

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

- IV-Q. La méthode getOnlyElement

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

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

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

- IV-S. La méthode isEmpty

- IV-T. La méthode limit

- IV-U. La méthode mergeSorted

- IV-V. La méthode paddedPartition

- IV-W. La méthode partition

- IV-X. La méthode removeAll

- IV-Y. La méthode removeIf

- IV-Z. La méthode retainAll

- IV-AA. La méthode size

- IV-AB. La méthode skip

- IV-AC. La méthode toArray

- IV-AD. La méthode toString

- IV-AE. La méthode transform

- IV-AF. La méthode tryFind

- IV-AG. La méthode unmodifiableIterable

- V. Conclusion

- VI. Remerciements

I - Introduction

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 sur l’exploration de la bibliothèque Guava de Google reprends l’ensemble des méthodes statiques composant la classe utilitaire Iterables.

II - Ajouter Google Guava à votre projet (Rappel)

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 avec Maven

1. <!-- https://mvnrepository.com/artifact/com.google.guava/guava -->

2. <dependency>

3. <groupId>com.google.guava</groupId>

4. <artifactId>guava</artifactId>

5. <version>30.1-jre</version>

6. </dependency>

III - 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.

IV - Implémentation des méthodes de la classe Iterables

IV-A - Les imports

Les imports

1. import com.google.common.collect.ImmutableList;

2. import com.google.common.collect.Iterables;

3. import static java.lang.System.out;

4. import java.util.ArrayList;

5. import java.util.Arrays;

6. import java.util.Collection;

7. import java.util.Comparator;

8. import java.util.Iterator;

9. import java.util.LinkedList;

10. import java.util.List;

11. import java.util.Optional;

12. import java.util.Queue;

13. import java.util.function.Function;

14. import java.util.function.Predicate;

IV-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

1. public final class Application {

3. // constantes

4. private final static int NB_MARQUES_VEHICULES = 5;

5. private final static int NB_PEINTURES_VEHICULES = 5;

6. private final static int NB_VEHICULES = 3;

7. // predicates

8. private final static Predicate<String> marquePeugeot;

9. private final static Predicate<String> marqueOpel;

10. private final static Predicate<String> marqueRenault;

11. private final static Predicate<String> marqueMitsubishi;

13. // structures de données

14. private final static List<String> vehicules;

15. private final static List<Number> consommations;

16. private final static String[] peugeot;

17. private final static String[] opel;

18. private final static String[] peinture;

20. static {

21. peugeot = new String[NB_VEHICULES];

22. peugeot[0] = "Peugeot Nouvelle SUV 3008";

23. peugeot[1] = "Peugeot Nouvelle SUV 5008";

24. peugeot[2] = "Peugeot Traveller/Expert Combi";

26. opel = new String[NB_VEHICULES];

27. opel[0] = "Opel Calibra";

28. opel[1] = "Opel Ascona";

29. opel[2] = "Opel Corsa";

31. peinture = new String[NB_PEINTURES_VEHICULES];

32. peinture[0] = "Gris Shark";

33. peinture[1] = "Gris Thorium";

34. peinture[2] = "Bourrasque";

35. peinture[3] = "Bleu Encre";

36. peinture[4] = "Noir Obsidien";

38. vehicules = new ArrayList<>(NB_MARQUES_VEHICULES);

39. }

41. static { // la consommation du litre/100km

42. final Byte deuxLitre100km = 2;

43. final Short troisLitre100km = 3;

44. consommations = new ArrayList<>();

45. consommations.add(deuxLitre100km);

46. consommations.add(troisLitre100km);

47. consommations.add(4.3d); // Double

48. consommations.add(5.8f); // Float

49. consommations.add(6); // Integer

50. consommations.add(7L); // Long

51. consommations.add(8.5f); // Float

52. consommations.add(9.2d); // Double

53. consommations.add(9); // Integer

54. consommations.add(9.7d); // Double

55. consommations.add(10L); // Long

56. }

58. static { // predicates

59. marquePeugeot = v -> v.contains("Peugeot");

60. marqueOpel = v -> v.contains("Opel");

61. marqueRenault = v -> v.contains("Renault");

62. marqueMitsubishi = v -> v.contains("Mitsubishi");

63. }

65. static Iterable<String> iterableVehicules = new ArrayList<>(NB_MARQUES_VEHICULES);

66. final static List<String> couleurs = Arrays.asList(new String[]{

67. "Blanc Banquise", "Rouge Lucifer", "Gris Graphite", "Gris Futura", "Bleu de Sevres",

68. "Noir Perla", "Gris Alluminium", "Rouge Aden", "Blanc Perle", "Bleu Lucia", "Gris Futura"});

70. final static Iterable<String> iterableRenault

71. = Arrays.asList(new String[]{"Renault Kangoo VP", "Renault Nouveau Grand Scenic", "Renault Alaskan"});

72. final static Iterable<String> iterableCitroen

73. = Arrays.asList(new String[]{"Citroen Nouvelle C-Elysée", "Citroen Nemo Multispace", "Citroen C4 Aircross"});

74. final static Iterable<String> iterableToyota

75. = Arrays.asList(new String[]{"Toyota Auris", "Toyota Nouvelle Yaris", "Toyota Aygo X "});

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

79. public static void main(String[] args) {

80. // commençons par afficher les véhicules de la marque peugeot

81. out.println(Arrays.asList(peugeot)); // [Peugeot Nouvelle SUV 3008, Peugeot Nouvelle SUV 5008, Peugeot Traveller/Expert Combi]

82. }

83. }

IV-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)

1. final boolean addAllVehicules = Iterables.addAll(vehicules, Arrays.asList(peugeot));

2. out.println(addAllVehicules); // true

IV-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)

1. // Attention : il s'agit du Predicate de Google Guava et pas celui du JDK !!!

2. // Predicate where a com.google.common.base.Predicate is expected, use the method reference predicate::test.

3. final boolean allMarquePeugeot = Iterables.all(vehicules, marquePeugeot::test);

4. out.println(allMarquePeugeot); // true

5. vehicules.add("Opel Calibra"); // on ajoute un véhicule qui n'est pas de la marque Peugeot

6. out.println(Iterables.all(vehicules, marquePeugeot::test)); // false

IV-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)

1. out.println(Iterables.any(vehicules, marqueOpel::test)); // true puisque nous avons ajouté précédemment un véhicule de la marque Opeml

2. out.println(Iterables.any(vehicules, marqueRenault::test)); // false car on n'a pas ajouté de vehicule de la marque Renault

IV-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)

1. iterableVehicules = Iterables.concat(iterableRenault);

2. out.println(iterableVehicules);

3. iterableVehicules = Iterables.concat(iterableRenault, iterableCitroen);

4. out.println(iterableVehicules);

5. iterableVehicules = Iterables.concat(iterableRenault, iterableCitroen, iterableToyota);

6. out.println(iterableVehicules);

7. iterableVehicules = Iterables.concat(iterableRenault, iterableCitroen, iterableToyota, Arrays.asList(opel));

8. out.println(iterableVehicules);

9. /*

10. [Renault Kangoo VP, Renault Nouveau Grand Scenic, Renault Alaskan]

11. [Renault Kangoo VP, Renault Nouveau Grand Scenic, Renault Alaskan, Citroen Nouvelle C-Elysée, Citroen Nemo Multispace, Citroen C4 Aircross]

12. [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 ]

13. [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]

14. */

IV-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)

1. final Queue<String> queueCodesCouleurs = new LinkedList<>(couleurs);

2. final Iterator<String> iterator = Iterables.consumingIterable(queueCodesCouleurs).iterator();

3. int index = 0;

4. while (iterator.hasNext() && index < 5) { // on ne veut afficher que les 5 premières couleurs

5. final String couleur = iterator.next();

6. out.println(couleur);

7. index++;

8. }

9. /*

10. Blanc Banquise

11. Rouge Lucifer

12. Gris Graphite

13. Gris Futura

14. Bleu de Sevres

15. */

IV-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)

1. final boolean containsRougeAden = Iterables.contains(couleurs, "Rouge Aden");

2. out.println(containsRougeAden); // true

IV-I - La méthode cycle

IV-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)

1. final Iterable<String> iterableCouleurs = Iterables.cycle(couleurs);

2. out.println(iterableCouleurs);

3. // [Blanc Banquise, Rouge Lucifer, Gris Graphite, Gris Futura, Bleu de Sevres, Noir Perla, Gris Alluminium, Rouge Aden, Blanc Perle, Bleu Lucia, Gris Futura] (cycled)

IV-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)

1. final Iterable<String> iterableCarburant = Iterables.cycle("Electric", "Diesel", "GNV", "Hybride");

2. out.println(iterableCarburant);

3. //[Electric, Diesel, GNV, Hybride] (cycled)

IV-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

1. final Iterable<String> iterableCarburantEssence = ImmutableList.of("Essence");

2. final Iterable<String> iterableCarburantEssenceSP = ImmutableList.of("Essence", "Essence Sans Plomb 95", "Essence Sans Plomb 98");

3. final boolean elementsEqualCarburantsEssenceSP = Iterables.elementsEqual(iterableCarburantEssence, iterableCarburantEssenceSP);

4. out.println(elementsEqualCarburantsEssenceSP); // false

IV-K - La méthode filter

IV-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)

1. final Iterable<Float> consomationsFilteredByDesiredType = Iterables.filter(consommations, Float.class);

2. out.println(consomationsFilteredByDesiredType); // [5.8, 8.5]

IV-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)

1. final Iterable<String> consommationsFilteredByPredicate = Iterables.filter(iterableVehicules, marqueRenault::test);

2. out.println(consommationsFilteredByPredicate); // [Renault Kangoo VP, Renault Nouveau Grand Scenic, Renault Alaskan]

3. // si le test du predicate est false alors la méthode filter renvoie []. Exemple: marquePeugeot::test

IV-L - La méthode find

IV-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)

1. // on crée un iterable de la marque Peugeot

2. final Iterable<String> iterablePeugeot = Iterables.concat(Arrays.asList(peugeot));

3. final String defaultValue = "Peugeot 308 CC";

4. final String findWithPredicateOrDefaultValue = Iterables.find(iterablePeugeot, marquePeugeot::test, defaultValue);

5. // la marque Renault n'étant pas ajoutée à notre iterableVehicules, la valeur par défaut est renvoyée

6. //String findWithPredicateOrDafaultValue = Iterables.find(iterableVehicules, marqueRenault::test, defaultValue);

7. out.println(findWithPredicateOrDefaultValue);

8. // Peugeot Nouvelle SUV 3008

IV-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)

1. final String findWithPredicate = Iterables.find(iterablePeugeot, marquePeugeot::test);

2. out.println(findWithPredicate); // Peugeot Nouvelle SUV 3008

IV-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)

1. final int frequencyCouleurs = Iterables.frequency(couleurs, "Gris Futura");

2. out.println(frequencyCouleurs); // 2

3. //final long frequencyCouleursStream = couleurs.stream().filter(Predicate.isEqual("Gris Futura")).count();

4. //out.println(frequencyCouleursStream); // 2

IV-N - La méthode get

IV-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)

1. //final String getCouleurOrDefaultValue = Iterables.get(iterableVehicules, 3, defaultValue);

2. //out.println(getCouleurOrDefaultValue); // Citroen Nouvelle C-Elysée

3. final String getCouleurOrDefaultValue = Iterables.get(iterableVehicules, 14, defaultValue);

4. out.println(getCouleurOrDefaultValue); // Peugeot 308 CC

IV-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)

1. final String getVehiculeToyota = Iterables.get(iterableToyota, 2); // Toyota Aygo X

2. out.println(getVehiculeToyota);

IV-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)

1. final String getFirstVehiculePeugeot = Iterables.getFirst(iterablePeugeot, defaultValue);

2. out.println(getFirstVehiculePeugeot);

3. // on instancie un nouvel iterable de véhicules de la marque Volkswagen

4. Iterable<String> iterableVolkswagen = new ArrayList<>(NB_MARQUES_VEHICULES);

5. // on n'ajoute aucun véhicule à cette liste, on la laisse vide

6. final String defaultVolkswagen = "Volkswagen Passat"; // le véhicule Volkswagen par défaut

7. final String getFirstVehiculeVolkswagen = Iterables.getFirst(iterableVolkswagen, defaultVolkswagen);

8. out.println(getFirstVehiculeVolkswagen);

IV-P - La méthode getLast

IV-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)

1. final String getLastVehiculePeugeot = Iterables.getLast(iterablePeugeot, defaultValue);

2. out.println(getLastVehiculePeugeot);

IV-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)

1. final String getLastVehicule = Iterables.getLast(iterableVehicules);

2. out.println(getLastVehicule); // Opel Corsa

IV-Q - La méthode getOnlyElement

IV-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)

1. final List<String> iterableMitsubishi = new ArrayList<>(NB_MARQUES_VEHICULES);

2. iterableMitsubishi.add("Mitsubishi Outlander PHEV"); // iterableMitsubishi contient un élément

3. final String defaultMitsubishi = "Mitsubishi ASX"; // le véhicule par défaut de la marque Mitsubishi

4. final String getOnlyElementVehiculeMitsubishiWithoutDefaultValue = Iterables.getOnlyElement(iterableMitsubishi, defaultMitsubishi);

5. // le véhicule ajouté sera affiché et pas celui par défaut

6. out.println(getOnlyElementVehiculeMitsubishiWithoutDefaultValue); // Mitsubishi Outlander PHEV

7. iterableMitsubishi.clear(); // on nettoie le contenu de iterableMitsubishi donc il n'y a plus aucun véhicule

8. final String getOnlyElementVehiculeMitsubishiWithDefaultValue = Iterables.getOnlyElement(iterableMitsubishi, defaultMitsubishi);       out.println(getOnlyElementVehiculeMitsubishiWithDefaultValue); // Mitsubishi ASX

IV-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)

1. iterableMitsubishi.add("Mitsubishi Outlander"); // on ajoute un véhicule à iterableMitsubishi

2. final String getOnlyElementVehiculeMitsubishi = Iterables.getOnlyElement(iterableMitsubishi);

3. out.println(getOnlyElementVehiculeMitsubishi); // Mitsubishi Outlander

IV-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)

1. final int indexOfVehiculeWithPredicate = Iterables.indexOf(iterableVehicules, marqueOpel::test);

2. out.println(indexOfVehiculeWithPredicate); // 9

3. final int indexOfVoitureWithPredicate = Iterables.indexOf(iterableVehicules, marqueMitsubishi::test);

4. out.println(indexOfVoitureWithPredicate); // -1

IV-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)

1. final boolean isEmptyVehiculeToyota = Iterables.isEmpty(iterableToyota); // !vehicules.stream().findAny().isPresent();

2. out.println(isEmptyVehiculeToyota); // false

3. final boolean isEmptyVehiculeVolkswagen = Iterables.isEmpty(iterableVolkswagen);

4. out.println(isEmptyVehiculeVolkswagen); // true

IV-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)

1. final Iterable<String> limitTypeCarburants = Iterables.limit(iterableCarburant, 4);

2. out.println(limitTypeCarburants); // [Electric, Diesel, GNV, Hybride]

IV-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)

1. // on ajoute le véhicule Volkwagen par défaut dans notre iterableVolkswagen

2. iterableVolkswagen = Arrays.asList(new String[]{defaultVolkswagen});

3. // nous voulons effectuer un tri en fonction de la longueur du nom du véhicule du plus long au plus court

4. final Comparator<String> comparator = (String o1, String o2) -> (o2.length() - o1.length());

5. final Iterable<String> mergedSortedWithComparator = Iterables.mergeSorted(ImmutableList.of(iterableMitsubishi, iterableVolkswagen), comparator);

6. out.println(mergedSortedWithComparator); // [Mitsubishi Outlander, Volkswagen Passat]

IV-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)

1. final Iterable<List<String>> paddedPartitionVehicules = Iterables.paddedPartition(iterableVehicules, NB_VEHICULES);

2. 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]]

IV-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)

1. final Iterable<List<String>> partitionVehicules = Iterables.partition(iterableVehicules, 5);

2. 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]]

IV-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)

1. final List<String> iterablePaletteCouleurs = new ArrayList<>(peinture.length);

2. iterablePaletteCouleurs.addAll(Arrays.asList(peinture));

3. final Collection<String> couleursToRemove = new ArrayList<>();

4. couleursToRemove.add("Bourrasque");

5. couleursToRemove.add("Rouge Lucifer");

6. out.println(iterablePaletteCouleurs); // [Gris Shark, Gris Thorium, Bourrasque, Bleu Encre, Noir Obsidien]

7. final boolean removeAllCouleurs = Iterables.removeAll(iterablePaletteCouleurs, couleursToRemove);

8. out.println(removeAllCouleurs); // true

IV-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)

1. // Java 8 users: if removeFrom is a Collection, use removeFrom.removeIf(predicate) instead.

2. out.println(vehicules);

3. final boolean removeIfFoundMarqueRenault = vehicules.removeIf(marqueRenault::test);

4. out.println(removeIfFoundMarqueRenault); // false

5. final boolean removeIfFoundMarqueOpel = vehicules.removeIf(marqueOpel::test);

6. out.println(removeIfFoundMarqueOpel); // true

IV-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)

1. final Collection<String> couleursToRetain = new ArrayList<>();

2. // on ajoute deux nouveaux coloris

3. couleursToRetain.add("Bleu Californium");

4. couleursToRetain.add("Gris Baryum");

5. // ... que l'on souhaite retenir pour la nouvelle collection

6. iterablePaletteCouleurs.add("Bleu Californium");

7. iterablePaletteCouleurs.add("Gris Baryum");

8. out.println(iterablePaletteCouleurs); // [Gris Shark, Gris Thorium, Bleu Encre, Noir Obsidien, Bleu Californium, Gris Baryum]

9. final boolean retainAllPeinture = Iterables.retainAll(iterablePaletteCouleurs, couleursToRetain);

10. out.println(retainAllPeinture); // true car on a pu retenir nos coloris sélectionnés

11. out.println(iterablePaletteCouleurs); // [Bleu Californium, Gris Baryum]

IV-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)

1. final int nombreVehicules = Iterables.size(iterableVehicules);

2. out.println(nombreVehicules); // 12

IV-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)

1. final Iterable<String> skipVehicules = Iterables.skip(iterableVehicules, NB_VEHICULES);

2. // on ne veut pas les 3 premiers véhicules, mais uniquement les 9 autres

3. 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]

IV-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)

1. final String[] toArrayVehicules = Iterables.toArray(iterableVehicules, String.class);

2. 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]

IV-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)

1. out.println(Iterables.toString(iterableToyota)); // [Toyota Auris, Toyota Nouvelle Yaris, Toyota Aygo X ]

IV-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)

1. // on décide d'augmenter le diamètre des jantes des véhicules

2. final Function<Integer, Float> multiplier = t -> t * 1.14f;

3. final Iterable<Float> augmenterDiametreJantes = Iterables.transform(iterableDiametreJantes, multiplier::apply);

4. out.println(augmenterDiametreJantes); // [14.82, 15.96, 17.1, 18.24, 19.38, 20.52]

IV-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)

1. out.println(iterableVehicules);

2. // équivaut à vehicules.stream().filter(marqueRenault::test).findFirst() donc renvoie le premier élément trouvé

3. final Optional<String> tryFindMarqueRenault = Iterables.tryFind(iterableVehicules, marqueRenault::test).toJavaUtil();

4. 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]

IV-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)

1. final Iterable<String> unmodifiableIterableVehicules = Iterables.unmodifiableIterable(iterableCarburantEssenceSP);

2. out.println(unmodifiableIterableVehicules); // [Essence, Essence Sans Plomb 95, Essence Sans Plomb 98]

V - 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.

VI - 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.