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 reprend l’ensemble des méthodes statiques composant la classe utilitaire Sets.
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.
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>
III. La classe utilitaire Sets▲
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 peut 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 Sets▲
IV-A. Les imports▲
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
import
com.google.common.collect.ImmutableList;
import
com.google.common.collect.ImmutableSet;
import
com.google.common.collect.Range;
import
com.google.common.collect.Sets;
import
static
java.lang.System.out;
import
java.util.Arrays;
import
java.util.Comparator;
import
java.util.EnumSet;
import
java.util.HashSet;
import
java.util.Iterator;
import
java.util.List;
import
java.util.NavigableSet;
import
java.util.Set;
import
java.util.SortedSet;
import
java.util.TreeSet;
import
java.util.concurrent.CopyOnWriteArraySet;
import
java.util.function.Predicate;
import
java.util.function.Supplier;
import
java.util.stream.Collector;
import
java.util.stream.Collectors;
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.
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.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
public
final
class
Application {
// les constantes
private
final
static
int
NB_MARQUES_VEHICULES =
5
;
private
final
static
int
NB_COULEURS_VEHICULES =
5
;
private
final
static
int
NB_VEHICULES =
3
;
// les enums
private
final
static
Enum categorie, marque, modele, annee, cylindree, puissance, soupapes, injection;
private
static
enum
Caracteristique {
CATEGORIE,
MARQUE,
MODELE,
ANNEE,
CYLINDREE,
PUISSANCE,
SOUPAPES,
INJECTION
}
static
{
// caractéristiques constructeur
categorie =
Caracteristique.CATEGORIE;
marque =
Caracteristique.MARQUE;
modele =
Caracteristique.MODELE;
annee =
Caracteristique.ANNEE;
// caractéristiques motrice
cylindree =
Caracteristique.CYLINDREE;
puissance =
Caracteristique.PUISSANCE;
soupapes =
Caracteristique.SOUPAPES;
injection =
Caracteristique.INJECTION;
}
private
static
enum
Marque {
CITROEN,
OPEL,
PEUGEOT,
RENAULT,
TOYOTA,
VOLKSWAGEN,
MITSUBISHI
}
private
final
static
String[] peugeot;
private
final
static
String[] opel;
private
final
static
String[] toyota;
private
final
static
String[] renault;
private
final
static
String[] citroen;
private
final
static
HashSet<
String>
vehicules;
static
{
// les structures de données
peugeot =
new
String[NB_VEHICULES];
peugeot[0
] =
"Peugeot Nouvelle 208"
;
peugeot[1
] =
"Peugeot Traveller/Expert Combi"
;
peugeot[2
] =
"Peugeot Nouvelle SUV 5008"
;
toyota =
new
String[NB_VEHICULES];
toyota[0
] =
"Toyota Nouvelle Yaris"
;
toyota[1
] =
"Toyota Avensis"
;
toyota[2
] =
"Toyota Nouvelle Landcruiser"
;
renault =
new
String[NB_VEHICULES];
renault[0
] =
"Renault Clio"
;
renault[1
] =
"Renault Nouveau Grand Scenic"
;
renault[2
] =
"Renault Arkana"
;
citroen =
new
String[NB_VEHICULES];
citroen[0
] =
"Citroën Nouvelle C3"
;
citroen[1
] =
"Citroën Berlingo"
;
citroen[2
] =
"Citroën Space Tourer Business Lounge"
;
opel =
new
String[NB_VEHICULES];
opel[0
] =
"Opel Corsa"
;
opel[1
] =
"Opel Zafira"
;
opel[2
] =
"Opel Crossland X"
;
vehicules =
new
HashSet<>(
NB_MARQUES_VEHICULES);
vehicules.addAll
(
Arrays.asList
(
peugeot));
}
// les predicats
private
final
static
Predicate<
String>
marqueVolkswagen;
private
final
static
Predicate<
String>
contientCouleurGris;
private
final
static
Predicate<
String>
marqueMitsubishi;
static
{
contientCouleurGris =
c ->
c.contains
(
"Gris"
);
marqueVolkswagen =
v ->
v.contains
(
"Volkswagen"
);
marqueMitsubishi =
v ->
v.contains
(
"Mitsubishi"
);
}
private
final
static
HashSet<
String>
couleurs;
static
{
// les différentes peintures
couleurs =
new
HashSet<>(
NB_COULEURS_VEHICULES);
couleurs.add
(
"Gris Graphite"
);
couleurs.add
(
"Gris Futura"
);
couleurs.add
(
"Rouge Aden"
);
couleurs.add
(
"Gris Thorium"
);
couleurs.add
(
"Noir Obsidien"
);
}
private
final
static
HashSet<
String>
peintures;
static
{
// les différents coloris
peintures =
new
HashSet<>(
);
peintures.add
(
"Noir Obsidien"
);
peintures.add
(
"Gris Thorium"
);
peintures.add
(
"Gris Cassiopée"
);
peintures.add
(
"Gris Cassiopée"
); // un élément dupliqué ?!
peintures.add
(
"Gris Manitoba"
);
peintures.add
(
"Gris Shark"
);
peintures.add
(
"Bourrasque"
);
peintures.add
(
"Bourrasque"
); // un autre élément dupliqué ?!
peintures.add
(
"Bleu Encre"
);
}
private
final
static
HashSet<
String>
carburants;
static
{
// les types de carburants
carburants =
new
HashSet<>(
);
carburants.add
(
"Essence"
);
carburants.add
(
"Diesel"
);
carburants.add
(
"GNV"
); // Gaz naturel pour véhicules
carburants.add
(
"Hybride"
);
carburants.add
(
"Biodiesel"
);
carburants.add
(
"Electric"
);
}
private
final
static
NavigableSet<
String>
mitsubishi;
static
{
mitsubishi =
new
TreeSet<>(
);
mitsubishi.add
(
"Mitsubishi Space Star"
);
mitsubishi.add
(
"Mitsubishi Outlander"
);
mitsubishi.add
(
"Mitsubishi Outlander PHEV"
);
mitsubishi.add
(
"Mitsubishi L200"
);
mitsubishi.add
(
"Mitsubishi Eclipse Cross PHEV"
);
mitsubishi.add
(
"Mitsubishi SUV ASX"
);
}
private
final
static
SortedSet<
String>
volkswagen;
static
{
volkswagen =
new
TreeSet<>(
);
volkswagen.add
(
"Volkswagen Polo"
);
volkswagen.add
(
"Volkswagen Golf"
);
volkswagen.add
(
"Volkswagen Passat"
);
volkswagen.add
(
"Volkswagen Tiguan"
);
volkswagen.add
(
"Volkswagen Caddy"
);
volkswagen.add
(
"Volkswagen Arteon"
);
volkswagen.add
(
"Volkswagen Amarok"
);
volkswagen.add
(
"Volkswagen Vitto"
);
volkswagen.add
(
"Volkswagen T-cross"
);
volkswagen.add
(
"Volkswagen Sharan"
);
}
private
final
static
Set<
String>
audi;
static
{
audi =
new
HashSet<>(
);
audi.add
(
"Audi A1 Sportback"
);
audi.add
(
"Audi Nouvelle A3 Sportback"
);
audi.add
(
"Audi A4 Berline"
);
audi.add
(
"Audi A5 Sportback"
);
audi.add
(
"Audi A6 Berline TFSI"
);
audi.add
(
"Audi A7 Sportback TFSI e"
);
audi.add
(
"Audi Nouvelle A8 L TFSI e"
);
}
private
final
static
Set<
Integer>
cylindrees; // en cm3
static
{
cylindrees =
Sets.newHashSet
(
);
cylindrees.add
(
999
);
cylindrees.add
(
1300
);
cylindrees.add
(
1461
);
cylindrees.add
(
1461
); // un élément dupliqué ?!
cylindrees.add
(
1560
);
cylindrees.add
(
1700
);
cylindrees.add
(
1983
);
cylindrees.add
(
2398
);
cylindrees.add
(
3400
);
cylindrees.add
(
3400
); // un autre élément dupliqué ?!
cylindrees.add
(
5500
);
cylindrees.add
(
5935
);
}
private
final
static
NavigableSet<
Integer>
puissances; // en kiloWatt
static
{
puissances =
new
TreeSet<>(
);
puissances.add
(
178
);
puissances.add
(
224
);
puissances.add
(
285
);
puissances.add
(
314
);
puissances.add
(
347
);
puissances.add
(
525
);
puissances.add
(
624
);
puissances.add
(
705
);
puissances.add
(
826
);
puissances.add
(
999
);
puissances.add
(
1300
);
}
public
static
void
main
(
String[] args) {
// commençons par afficher la liste des véhicules de la marque Peugeot
out.println
(
Arrays.asList
(
peugeot)); // [Peugeot Nouvelle 208, Peugeot Traveller/Expert Combi, Peugeot Nouvelle SUV 5008]
}
}
IV-C. La méthode cartesianProduct▲
Cette méthode permet de renvoyer toutes les listes possibles qui peuvent être formées en choisissant un élément de chacun des ensembles donnés dans l'ordre ; le "produit cartésien n-aire" des ensembles.
IV-C-1. cartesianProduct(Set<? extends B>... sets)▲
Nous voulons renvoyer toutes les listes possibles qui peuvent être formées en choisissant un élément de chacun des ensembles donnés dans l'ordre. En quelque sorte nous voulons afficher un produit cartésien d’un ensemble ordonné d’éléments. La méthode cartesianProduct(Set<? extends B>... sets) permet d’effectuer cette action.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
final
Set<
List<
String>>
immutableCartesianProduct =
Sets.cartesianProduct
(
vehicules, peintures);
// 1ère méthode : on utilise directement la méthode cartesianProduct(List<? extends Set<? extends B>> sets)
out.println
(
immutableCartesianProduct);
// 2ème méthode : on utilise une boucle pour parcourir les couples formés par le produit cartésien souhaité [véhicule, peinture]
final
List<
String>
peugeotMutableList =
Arrays.asList
(
peugeot);
peugeotMutableList.forEach
(
vehicule ->
{
peintures.stream
(
)
//.filter(carburant -> carburant.equals("Diesel")) // si on souhaite uniquement les véhicules "Diesel"
.map
(
peinture ->
ImmutableList.of
(
vehicule, peinture))
.forEachOrdered
(
couple ->
{
out.println
(
couple);
}
);
}
);
/*
[[Peugeot Traveller/Expert Combi, Gris Manitoba], [Peugeot Traveller/Expert Combi, Gris Shark], [Peugeot Traveller/Expert Combi, Bourrasque], [Peugeot Traveller/Expert Combi, Noir Obsidien], [Peugeot Traveller/Expert Combi, Gris Thorium], [Peugeot Traveller/Expert Combi, Gris Cassiopée], [Peugeot Traveller/Expert Combi, Bleu Encre], [Peugeot Nouvelle SUV 5008, Gris Manitoba], [Peugeot Nouvelle SUV 5008, Gris Shark], [Peugeot Nouvelle SUV 5008, Bourrasque], [Peugeot Nouvelle SUV 5008, Noir Obsidien], [Peugeot Nouvelle SUV 5008, Gris Thorium], [Peugeot Nouvelle SUV 5008, Gris Cassiopée], [Peugeot Nouvelle SUV 5008, Bleu Encre], [Peugeot Nouvelle 208, Gris Manitoba], [Peugeot Nouvelle 208, Gris Shark], [Peugeot Nouvelle 208, Bourrasque], [Peugeot Nouvelle 208, Noir Obsidien], [Peugeot Nouvelle 208, Gris Thorium], [Peugeot Nouvelle 208, Gris Cassiopée], [Peugeot Nouvelle 208, Bleu Encre]]
*/
IV-C-2. cartesianProduct(List<? extends Set<? extends B>> sets)▲
Une autre signature de cette méthode permet d’utiliser directement une liste immuable de sets eux-mêmes immuables.
2.
3.
4.
5.
6.
7.
8.
9.
final
Set<
List<
String>>
immutableCartesianProducts =
Sets.cartesianProduct
(
ImmutableList.of
(
ImmutableSet.of
(
citroen[0
], citroen[1
]),
ImmutableSet.of
(
"Gris Graphite"
, "Gris Shark"
, "Gris Manitoba"
))
);
out.println
(
immutableCartesianProducts);
/*
[[Citroën Nouvelle C3, Gris Graphite], [Citroën Nouvelle C3, Gris Shark], [Citroën Nouvelle C3, Gris Manitoba], [Renault Arkana, Gris Graphite], [Renault Arkana, Gris Shark], [Renault Arkana, Gris Manitoba]]
*/
IV-D. La méthode combinations▲
Nous voulons maintenant récupérer tous les sous-ensembles d’un ensemble d’une longueur que nous avons définie. La méthode combinations(Set<E> set, int size) permet d’effectuer cette opération.
2.
3.
4.
5.
6.
7.
8.
9.
10.
final
Set<
Set<
String>>
vehiculeCombinations =
Sets.combinations
(
peintures, 2
);
out.println
(
vehiculeCombinations); // Sets.combinations([Gris Manitoba, Gris Shark, Bourrasque, Noir Obsidien, Gris Thorium, Gris Cassiopée, Bleu Encre], 2)
out.println
(
vehiculeCombinations.size
(
)); // 21 combinaisons formées
/* {{Gris Manitoba, Gris Shark}, {Gris Manitoba, Bourrasque}, {Gris Manitoba, Noir Obsidien}, {Gris Manitoba, Gris Thorium}, {Gris Manitoba, Gris Cassiopée}, {Gris Manitoba, Bleu Encre}
,{Gris Shark, Bourrasque}, {Gris Shark, Noir Obsidien}, {Gris Shark, Gris Thorium}, {Gris Shark, Gris Cassiopée}, {Gris Shark, Bleu Encre}
,{Bourrasque, Noir Obsidien},{Bourrasque, Gris Thorium}, {Bourrasque, Gris Cassiopée}, {Bourrasque, Bleu Encre}
,{Noir Obsidien, Gris Thorium}, {Noir Obsidien, Gris Cassiopée}, {Noir Obsidien, Bleu Encre}
,{Gris Thorium, Gris Cassiopée},{Gris Thorium, Bleu Encre}
,{Gris Cassiopée, Bleu Encre}}
*/
IV-E. La méthode complementOf▲
Nous voulons désormais créer un EnumSet, c’est-à-dire une énumération d’un ensemble ordonné d’éléments récupérant toutes les valeurs qui ne sont pas dans une collection passée en paramètre. La méthode complementOf(Collection<E> collection) permet d’effectuer cette opération sans aucune difficulté.
2.
3.
4.
5.
6.
final
EnumSet<
Marque>
marquesFrancaises, complementOfMarquesFrancaises, complementOfMarquesEtrangeres;
marquesFrancaises =
EnumSet.of
(
Marque.CITROEN, Marque.PEUGEOT, Marque.RENAULT);
complementOfMarquesFrancaises =
EnumSet.complementOf
(
marquesFrancaises);
out.println
(
complementOfMarquesFrancaises); // [OPEL, TOYOTA, VOLKSWAGEN, MITSUBISHI]
complementOfMarquesEtrangeres =
EnumSet.complementOf
(
complementOfMarquesFrancaises);
out.println
(
complementOfMarquesEtrangeres); // [CITROEN, PEUGEOT, RENAULT]
IV-F. La méthode difference▲
Si nous souhaitons obtenir une vue non modifiable de la différence entre deux sets, la méthode difference(Set<E> set1, Set<?> set2) permet d’accomplir cette tâche.
2.
3.
final
Sets.SetView<
String>
colorisDifference =
Sets.difference
(
couleurs, peintures);
out.println
(
colorisDifference); // renvoi tous les éléments présents dans couleurs et qui ne sont pas dans peintures
// [Gris Graphite, Gris Futura, Rouge Aden]
IV-G. La méthode filter▲
Cette méthode permet de renvoyer les éléments non filtrés d'un NavigableSet, qui satisfont à un prédicat.
IV-G-1. filter(NavigableSet<E> unfiltered, Predicate<? super E> predicate)▲
Une première signature de cette méthode permet de renvoyer tous les éléments d’un NavigableSet qui répondent à une condition (un prédicat). Par exemple, nous voulons un filtre sur tous les véhicules de la marque Mitsubishi précisément.
2.
final
NavigableSet<
String>
filterMitsubishiVehicules =
Sets.filter
(
mitsubishi, marqueMitsubishi::test);
out.println
(
filterMitsubishiVehicules); // [Mitsubishi Eclipse Cross PHEV, Mitsubishi Outlander PHEV, Mitsubishi SUV ASX, Mitsubishi Space Star]
IV-G-2. filter(Set<E> unfiltered, Predicate<? super E> predicate)▲
Une autre signature permet cette fois-ci de renvoyer tous les éléments d’un Set qui répondent à un prédicat. Nous voulons toutes les peintures contenant du gris.
2.
final
Set<
String>
filterCouleursVehicules =
Sets.filter
(
peintures, contientCouleurGris::test);
out.println
(
filterCouleursVehicules); // [Gris Manitoba, Gris Shark, Gris Thorium, Gris Cassiopée]
IV-G-3. filter(SortedSet<E> unfiltered, Predicate<? super E> predicate)▲
Une autre signature permet cette fois-ci de renvoyer tous les éléments d’un SortedSet (un ensemble d’éléments triés) qui répondent à un prédicat. Nous voulons récupérer précisément tous les véhicules de la marque Volkswagen.
2.
final
SortedSet<
String>
filterVolkswagenVehicules =
Sets.filter
(
volkswagen, marqueVolkswagen::test);
out.println
(
filterVolkswagenVehicules); // [Volkswagen Amarok, Volkswagen Golf, Volkswagen Polo, Volkswagen Sharan, Volkswagen T-cross, Volkswagen Vitto]
IV-H. La méthode immutableEnumSet▲
Cette méthode permet de renvoyer une instance d'ensembles immuables contenant les éléments de l'énumération donnée.
IV-H-1. immutableEnumSet(E anElement, E... otherElements)▲
Une première signature de cette méthode permet de renvoyer une instance immuable d’un set contenant les éléments sélectionnés d’une énumération. Le second paramètre de cette méthode est une ellipse afin que l’on puisse ajouter plusieurs éléments de l’énumération. Nous décidons d’agréger la catégorie, la marque, le modèle et l’année d’un véhicule.
2.
final
ImmutableSet<
String>
immutableEnumSetConstructeur =
Sets.immutableEnumSet
(
categorie, marque, modele, annee);
out.println
(
immutableEnumSetConstructeur); // [CATEGORIE, MARQUE, MODELE, ANNEE]
IV-H-2. immutableEnumSet(Iterable<E> elements)▲
Une seconde signature de cette méthode prend en unique paramètre un objet Iterable et renvoie tous les éléments de l’énumération qui ont été sélectionnés.
2.
3.
final
Iterable<
Caracteristique>
iterableCaracteristiqueRegalienne =
ImmutableList.of
(
Caracteristique.CATEGORIE, Caracteristique.MARQUE, Caracteristique.MODELE, Caracteristique.ANNEE);
final
ImmutableSet<
Caracteristique>
immutableEnumSetCaracteristiqueVehicules =
Sets.immutableEnumSet
(
iterableCaracteristiqueRegalienne);
out.println
(
immutableEnumSetCaracteristiqueVehicules); // [CATEGORIE, MARQUE, MODELE, ANNEE]
IV-I. La méthode intersection▲
Admettons que nous voulions connaître les éléments communs à deux ensembles. Pour cela nous utilisons la méthode intersection(Set<E> set1, Set<?> set2).
2.
final
Sets.SetView<
String>
intersectionColoris =
Sets.intersection
(
couleurs, peintures);
out.println
(
intersectionColoris); // [Noir Obsidien, Gris Thorium]
IV-J. La méthode newConcurrentHashSet▲
Cette méthode permet d’instancier un HashSet pouvant fonctionner correctement dans un environnement concurrentiel tout en s’appuyant sur une table de hachage.
IV-J-1. newConcurrentHashSet()▲
Nous pouvons également instancier un type HashSet sécurisé (c’est-à-dire pouvant s’utiliser dans un environnement concurrentiel sans altération des données) s’appuyant sur une table de hachage. La méthode newConcurrentHashSet() permet d’effectuer cette action.
2.
3.
4.
5.
6.
final
Set<
String>
newConcurrentHashSetVehicules =
Sets.newConcurrentHashSet
(
);
newConcurrentHashSetVehicules.add
(
"Citroën Space Tourer Business Lounge"
);
newConcurrentHashSetVehicules.add
(
"Renault Talisman Estate"
);
newConcurrentHashSetVehicules.add
(
"Opel Meriva"
);
newConcurrentHashSetVehicules.add
(
"Nouvelle Peugeot 508"
);
out.println
(
newConcurrentHashSetVehicules); // [Opel Meriva, Audi A8 L, Nouvelle Peugeot 508, Citroën Space Tourer Business Lounge, Renault Talisman Estate]
IV-J-2. newConcurrentHashSet(Iterable<? extends E> elements)▲
Cette méthode possède également une autre variante prenant comme paramètre un Iterable ; cette variante quant à elle nous permet de créer un HashSet directement avec nos véhicules.
2.
final
Set<
String>
newConcurrentHashSetVehiculesAudi =
Sets.newConcurrentHashSet
(
audi);
out.println
(
newConcurrentHashSetVehiculesAudi); // [Audi A4 Berline, Audi A6 Berline TFSI, Audi A5 Sportback, Audi A1 Sportback, Audi Nouvelle A8 L TFSI e, Audi Nouvelle A3 Sportback, Audi A7 Sportback TFSI e]
IV-K. La méthode newCopyOnWriteArraySet▲
Cette méthode permet de créer une instance vide de CopyOnWriteArraySet.
IV-K-1. newCopyOnWriteArraySet()▲
Nous pouvons également créer une instance vide de la classe CopyOnWriteArraySet.
2.
final
CopyOnWriteArraySet<
String>
newCopyOnWriteArraySetVide =
Sets.newCopyOnWriteArraySet
(
); // une instance vide de la classe CopyOnWriteArraySet
out.println
(
newCopyOnWriteArraySetVide); // []
IV-K-2. newCopyOnWriteArraySet(Iterable<? extends E> elements)▲
Une autre signature de cette méthode permet de passer en paramètre un Iterable contenant les éléments donnés.
2.
final
CopyOnWriteArraySet<
String>
newCopyOnWriteArraySetVehiculesAudi =
Sets.newCopyOnWriteArraySet
(
newConcurrentHashSetVehiculesAudi);
out.println
(
newCopyOnWriteArraySetVehiculesAudi); // [Audi A4 Berline, Audi A6 Berline TFSI, Audi A5 Sportback, Audi A1 Sportback, Audi Nouvelle A8 L TFSI e, Audi Nouvelle A3 Sportback, Audi A7 Sportback TFSI e]
IV-L. La méthode newEnumSet▲
Si nous souhaitons instancier un objet de type EnumSet mutable, nous pouvons utiliser cette méthode en lui passant comme paramètres des éléments Iterables.
2.
3.
final
Iterable<
Caracteristique>
iterableCaracteristiqueMotrice =
ImmutableList.of
(
Caracteristique.CYLINDREE, Caracteristique.SOUPAPES, Caracteristique.INJECTION, Caracteristique.PUISSANCE);
final
EnumSet<
Caracteristique>
enumSetCaracteristiqueVehicules =
Sets.newEnumSet
(
iterableCaracteristiqueMotrice, Caracteristique.class
);
out.println
(
enumSetCaracteristiqueVehicules); // [CYLINDREE, PUISSANCE, SOUPAPES, INJECTION]
IV-M. La méthode newHashSet▲
Cette méthode permet de créer une instance mutable HashSet, initialement vide.
IV-M-1. newHashSet()▲
Nous pouvons également créer une instance vide de la classe HashSet.
2.
final
HashSet<
String>
newHashSet =
Sets.newHashSet
(
);
out.println
(
newHashSet); // []
IV-M-2. newHashSet(E... elements)▲
Une autre signature de cette méthode permet de passer en paramètres des éléments donnés.
2.
final
Set<
Integer>
newHashSetWithElements =
Sets.newHashSet
(
cylindrees);
out.println
(
newHashSetWithElements); // [1300, 1700, 1461, 999, 1560, 3400, 5500, 2398, 1983, 5935]
IV-M-3. newHashSet(Iterable<? extends E> elements)▲
Une autre signature de cette méthode permet de passer en paramètre un objet de type Iterable.
2.
final
Set<
String>
newHashSetWithIterable =
Sets.newHashSet
(
newConcurrentHashSetVehiculesAudi);
out.println
(
newHashSetWithIterable); // [Audi A4 Berline, Audi A6 Berline TFSI, Audi A5 Sportback, Audi A1 Sportback, Audi Nouvelle A8 L TFSI e, Audi Nouvelle A3 Sportback, Audi A7 Sportback TFSI e]
IV-M-4. newHashSet(Iterator<? extends E> elements)▲
Une autre signature de cette méthode permet de passer en paramètre un objet de type Iterator.
2.
3.
final
Iterator<
String>
iteratorMitsubishi =
mitsubishi.iterator
(
);
final
Set<
String>
newHashSetWithIterator =
Sets.newHashSet
(
iteratorMitsubishi);
out.println
(
newHashSetWithIterator); // [Mitsubishi SUV ASX, Mitsu L200, Mitsubishi Eclipse Cross PHEV, Mitsubishi Outlander PHEV, Mitsu Outlander, Mitsubishi Space Star]
IV-N. La méthode newHashSetWithExpectedSize▲
Nous pouvons également instancier un HashSet d’une taille prédéfinie. Cette opération est triviale.
2.
final
Set<
Integer>
newHashSetWithExpectedSize =
Sets.newHashSetWithExpectedSize
(
NB_VEHICULES);
out.println
(
newHashSetWithExpectedSize.size
(
)); // 0 car aucun élément n'a encore été ajouté. On peut ajouter un nombre d'éléments > NB_VEHICULES car un HashSet est une structure de données dynamique !
IV-O. La méthode newIdentityHashSet▲
On peut également créer un Set vide utilisant la fonctionnalité identity pour déterminer l’égalité par comparaison des références d’objets.
2.
final
Set<
String>
newIdentityHashSet =
Sets.newIdentityHashSet
(
);
out.println
(
newIdentityHashSet); // []
IV-P. La méthode newLinkedHashSet▲
Cette méthode permet de créer une instance mutable vide d’un LinkedHashSet.
IV-P-1. newLinkedHashSet()▲
Nous pouvons également créer une instance vide de la classe LinkedHashSet.
2.
final
Set<
String>
newLinkedHashSet =
Sets.newLinkedHashSet
(
);
out.println
(
newLinkedHashSet); // []
IV-P-2. newLinkedHashSet(Iterable<? extends E> elements)▲
Une autre signature de cette méthode permet de passer en paramètre un objet de type Iterable.
2.
final
Set<
Integer>
newLinkedHashSetWithIterable =
Sets.newLinkedHashSet
(
cylindrees);
out.println
(
newLinkedHashSetWithIterable); // // [1300, 1700, 1461, 999, 1560, 3400, 5500, 2398, 1983, 5935]
IV-Q. La méthode newLinkedHashSetWithExpectedSize▲
Nous pouvons également instancier un LinkedHashSet d’une taille prédéfinie. Cette opération est triviale.
2.
final
Set<
Integer>
newLinkedHashSetWithExpectedSize =
Sets.newLinkedHashSetWithExpectedSize
(
NB_VEHICULES);
out.println
(
newLinkedHashSetWithExpectedSize); // []
IV-R. La méthode newTreeSet▲
Cette méthode permet de créer une instance de TreeSet mutable et vide, triée selon l'ordre de tri naturel de ses éléments.
IV-R-1. newTreeSet()▲
Nous pouvons également créer une instance vide de la classe TreeSet.
2.
final
TreeSet<
String>
newTreeSet =
Sets.newTreeSet
(
);
out.println
(
newTreeSet); // []
IV-R-2. newTreeSet(Comparator<? super E> comparator)▲
Une autre signature de cette méthode permet de passer en paramètre un objet de type Comparator.
2.
3.
final
Comparator<
String>
comparator =
(
String o1, String o2) ->
(
o2.length
(
) -
o1.length
(
));
TreeSet<
String>
newTreeSetWithComparator =
Sets.newTreeSet
(
comparator);
out.println
(
newTreeSetWithComparator); // []
IV-R-3. newTreeSet(Iterable<? extends E> elements)▲
Une autre signature de cette méthode permet de passer en paramètre un objet de type Iterable. Nous souhaitons parcourir nos véhicules de la marque Volkswagen sous la forme d’un TreeSet.
2.
final
Set<
String>
newTreeSetWithIterable =
Sets.newTreeSet
(
volkswagen);
out.println
(
newTreeSetWithIterable); // [VW Arteon, VW Caddy, VW Passat, VW Tiguan, Volkswagen Amarok, Volkswagen Golf, Volkswagen Polo, Volkswagen Sharan, Volkswagen T-cross, Volkswagen Vitto]
IV-S. La méthode powerSet▲
Nous souhaitons renvoyer tous les sous-ensembles possibles d’un ensemble. La méthode powerSet(Set<E> set) permet d’effectuer cette opération. Imaginons que nous voulions tous les sous-ensembles des véhicules de la marque Mitshubishi.
2.
final
Set<
Set<
String>>
powerSet =
Sets.powerSet
(
mitsubishi);
out.println
(
powerSet); // powerSet({Mitsu L200=0, Mitsu Outlander=1, Mitsubishi Eclipse Cross PHEV=2, Mitsubishi Outlander PHEV=3, Mitsubishi SUV ASX=4, Mitsubishi Space Star=5})
IV-T. La méthode subSet▲
Nous pourrions tout aussi bien renvoyer une vue de la partie d'un ensemble dont les éléments sont contenus dans une plage définie. La méthode subSet(NavigableSet<K> set, Range<K> range) permet d’effectuer cette opération. Nous voulons les véhicules ayant une puissance moteur supérieure à 400.
2.
3.
final
Range<
Integer>
puissanceGreaterThan400 =
Range.greaterThan
(
400
);
final
NavigableSet<
Integer>
subSetPuissanceMoteur =
Sets.subSet
(
puissances, puissanceGreaterThan400);
out.println
(
subSetPuissanceMoteur); // [525, 624, 705, 826]
IV-U. La méthode symmetricDifference▲
Cette méthode renvoie une vue non modifiable de la différence symétrique de deux ensembles. Nous pouvons l’utiliser par exemple pour visualiser les cylindrées et les puissances moteur de nos véhicules.
2.
final
Sets.SetView<
Integer>
symmetricDifference =
Sets.symmetricDifference
(
cylindrees, puissances);
out.println
(
symmetricDifference); // [1700, 1461, 1560, 3400, 5500, 2398, 1983, 5935, 178, 224, 285, 314, 347, 525, 624, 705, 826] ==> 999 et 1300 sont absents
IV-V. La méthode synchronizedNavigableSet▲
Dans un environnement concurrentiel (où de nombreux fils d’exécution ont accès à une donnée en même temps), la méthode synchronizedNavigableSet(NavigableSet<E> navigableSet) permet de renvoyer un ensemble navigable synchronisé soutenu par l'ensemble navigable spécifié.
2.
final
NavigableSet<
Integer>
synchronizedNavigableSet =
Sets.synchronizedNavigableSet
(
puissances);
out.println
(
synchronizedNavigableSet); // [178, 224, 285, 314, 347, 525, 624, 705, 826, 999, 1300]
IV-W. La méthode toImmutableEnumSet▲
Imaginons que nous voulions renvoyer un collecteur qui accumulerait les éléments d'entrée dans un nouvel ImmutableSet avec une implémentation spécialisée pour les enums. La méthode toImmutableEnumSet() permet d’effectuer cette opération de façon triviale.
2.
3.
4.
final
ImmutableSet<
String>
immutableEnumSetMoteur =
Sets.immutableEnumSet
(
cylindree, puissance, soupapes, injection);
final
Supplier<
ImmutableSet<
String>>
collectionFactory =
(
) ->
immutableEnumSetMoteur;
final
Collector<
String, ?, ImmutableSet<
String>>
toImmutableEnumSet =
Collectors.toCollection
(
collectionFactory);
out.println
(
toImmutableEnumSet.supplier
(
).get
(
)); // [CYLINDREE, PUISSANCE, SOUPAPES, INJECTION]
IV-X. La méthode union▲
Il est également possible de renvoyer une vue non modifiable de l'union de deux ensembles en utilisant la méthode union(Set<? extends E> set1, Set<? extends E> set2). Nous voulons l’union des véhicules des marques Audi et Volkswagen.
2.
final
Sets.SetView<
String>
unionAudiVolkswagen =
Sets.union
(
audi, volkswagen);
out.println
(
unionAudiVolkswagen); // [Audi A4 Berline, Audi A6 Berline TFSI, Audi A5 Sportback, Audi A1 Sportback, Audi Nouvelle A8 L TFSI e, Audi Nouvelle A3 Sportback, Audi A7 Sportback TFSI e, Volkswagen Amarok, Volkswagen Arteon, Volkswagen Caddy, Volkswagen Golf, Volkswagen Passat, Volkswagen Polo, Volkswagen Sharan, Volkswagen T-cross, Volkswagen Tiguan, Volkswagen Vitto]
IV-Y. La méthode unmodifiableNavigableSet▲
Pour finir, nous si nous voulons renvoyer une vue non modifiable d’un ensemble navigable spécifié, la méthode unmodifiableNavigableSet(NavigableSet<E> set) permet d’effectuer cette opération.
2.
final
NavigableSet<
String>
unmodifiableNavigableSetMitsubishi =
Sets.unmodifiableNavigableSet
(
mitsubishi);
out.println
(
unmodifiableNavigableSetMitsubishi); // [Mitsu L200, Mitsu Outlander, Mitsubishi Eclipse Cross PHEV, Mitsubishi Outlander PHEV, Mitsubishi SUV ASX, Mitsubishi Space Star]
V. Conclusion▲
Nous avons fait le tour des méthodes utilitaires présentes dans la classe Sets. 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 matière de productivité.
VI. Remerciements▲
Je tiens à remercier tout particulièrement escartefigue pour la relecture orthographique de cet article.
Je remercie également la communauté developpez.com qui propose un forum d’entraide d’une richesse fortement appréciable. Sans oublier Mickael Baron qui donne de son temps pour s’occuper de la rubrique Java, RomeoBeni qui a écrit un ouvrage d’une rare simplicité pour apprendre à programmer en Java, mais aussi tous les membres répondant aux questions des débutants en programmation dont je faisais partie il y a quelques années de cela. Merci encore à tous.