Collection 01 : List
Au cours de ta vie de développeur, tu auras souvent à stocker, classer, trier des données. Dans tous les langages, tu pourras utiliser des tableaux, mais en Java il existe une classe, Collection, qui regroupe plusieurs outils bien pratiques.
Le problème, c'est qu'avec toutes les collections existantes, il est difficile de s'y retrouver et d'utiliser celle qui est adaptée.
Cette première quête va te présenter la plus connue : List.
Objectifs
- Comprendre les avantages des collections
- Savoir utiliser et parcourir une liste
List
Les tableaux, tu connais : c'est plutôt facile à utiliser, on stocke des données, on parcourt le tableau, et voilà.
Mais en Java, les tableaux ont un gros problème : ils ont une taille fixe !
-
Si tu veux créer un tableau vide et ajouter des éléments plus tard, tu dois décider dès le départ de sa taille maximale.
-
Si tu veux créer un tableau avec des éléments présents dès le départ, tu ne pourras pas en ajouter d'autre non plus.
Pour pallier ce problème, le Java te permet d'utiliser une Collection nommée List.
Dans une liste, les éléments sont toujours ordonnés, comme dans un tableau : chaque élément aura une position. Cependant, tu pourras insérer un élément à la fin ou au milieu de la liste (cela décalera alors les positions des autres éléments).
Mais List est une interface, c'est-à-dire qu'elle contient des comportements possibles (par exemple ajouter ou supprimer un élément), mais pas la façon dont ces comportements sont réalisés.
Afin de pouvoir créer une liste, il va te falloir utiliser une classe qui implémente List. Ça tombe bien, Java t'en fournit une : ArrayList.
ArrayList
Pour créer une nouvelle ArrayList vide, tu vas devoir créer une nouvelle instance de la classe et la stocker dans une référence :
ArrayList<Food> lunch = new ArrayList<>();
Ici le mot-clé new va créer une nouvelle instance et cette dernière sera stockée dans la référence lunch.
Tu remarques qu'il est possible de créer des listes de n'importe quel objet. Mais tu ne pourras pas instancier une ArrayList avec un type primitif. En clair : impossible d'instancier ArrayList<int> ou ArrayList<char>, par exemple.
Cependant, il existe des classes enveloppes (wrapper) pour chaque type primitif, ce qui permet de contourner le problème : tu pourras donc instancier ArrayList<Integer> ou ArrayList<Character> par exemple.
Utilisation et méthodes
1. Insertion
Maintenant que ta liste est créée, il serait utile d'y ajouter des éléments. Pour cela, tu vas utiliser une des méthodes de la classe ArrayList : add.
Food burger = new Food("Big Wac", 450);
Food fries = new Food("French fries", 275);
Food cheeseburger = new Food("Cheeseburger", 300);
Food sunday = new Food("Chocolate Sunday", 175);
ArrayList<Food> lunch = new ArrayList<>();
lunch.add(burger);
lunch.add(fries);
lunch.add(cheeseburger);
lunch.add(sunday);
2. Accès
À chaque insertion d'un élément dans la liste, un indice lui est associé. C'est cet index qui va permettre d'accéder à l'élément par la suite.
Reprenons l'exemple précédent, et voyons les indices correspondants :
lunch.add(burger); // indice 0
lunch.add(fries); // indice 1
lunch.add(cheeseburger); // indice 2
lunch.add(sunday); // indice 3
Donc si tu veux récupérer le second élément, il te faudra le code suivant :
Food stuff = lunch.get(1); // récupère fries
3. Suppression
De la même façon, tu peux supprimer un élément d'une liste avec son indice. Ainsi, les indices de tous les éléments suivants vont être modifiés pour prendre compte de cette modification :
lunch.add(burger); // indice 0
lunch.add(fries); // indice 1
lunch.add(cheeseburger); // indice 2
lunch.add(sunday); // indice 3
lunch.remove(1); // remove fries
Food stuff = lunch.get(1); // récupère cheeseburger, car les indices ont été décalés
4. Échange d'un élément
lunch.add(burger); // indice 0
lunch.add(fries); // indice 1
lunch.add(cheeseburger); // indice 2
lunch.add(sunday); // indice 3
Food milkshake = new Food("Vanilla Milkshake", 200);
lunch.set(3, milkshake); // remplace sunday par milkshake
5. Références et instances
Par abus de langage, on va dire qu'une ArrayList contient des éléments. Mais c'est faux ! En fait, la liste contient des références vers ces éléments. En clair, la liste contient des liens vers les objets, pas les objets eux-mêmes.
Si je t'en parle, ce n'est pas pour le simple plaisir : cela entraînera des comportements qui te sembleront étranges !
Food burger = new Food("Big Wac", 450);
ArrayList<Food> lunch = new ArrayList<>();
lunch.add(burger); // j'ajoute le burger "Big Wac" à la liste
burger.setName("Double Cheese"); // je modifie le nom du burger après qu'il a été ajouté à la liste
Food stuff = lunch.get(0); // je récupère le premier élément de la liste
System.out.println(stuff.getName()); // va afficher "Double Cheese"
6. Vider la liste
lunch.add(burger);
lunch.add(fries);
lunch.add(cheeseburger);
lunch.add(sunday);
lunch.clear(); // la liste est vide
7. Parcourir une liste
Tu vas y retrouver la boucle for classique en utilisant l'index, mais aussi la méthode for-each.
// boucle for
for (int i = 0; i < lunch.size(); i++) {
Food food = lunch.get(i);
}
// boucle for-each
for (Food food : lunch) {
// ...
}
8. Aller plus loin
Prends bien le temps de lire les documentations en ressources (comme tu dois toujours faire !) pour découvrir d'autres cas d'utilisation d'une liste. Ça te sera utile dans le challenge.
Avantages et inconvénients
La collection ArrayList a pour avantage de pouvoir contenir des doublons.
Si tu ne veux pas de doublons, que tu dois effectuer un tri sur la liste ou rechercher un élément spécifique, ces opérations vont être plus lentes qu'avec une autre collection : Set. Mais tu découvriras cela plus tard !
Afin de voir en situation toutes les notions abordées par la quête, récupère le dépôt git donné en ressource.
Il contient deux classes : Food et Fastfood. Tu compileras et exécuteras la dernière, afin de voir en détail :
-
l'instanciation d'une liste
-
les ajout, suppression et modification de la liste
-
la modification d'une instance en dehors de la liste (qui impacte tout de même l'élément correspondant dans la liste)
-
l'itération de la liste
Ensuite, ouvre ces deux classes pour regarder comment tout cela est organisé.
Challenge
Infinity War
Thanos décide de programmer son gant de l'infini afin de créer une liste de Hero, dans le but final d'en supprimer la moitié.
Pour démarrer, fais un Fork du dépôt suivant puis clone-le en local.
Pense bien à faire un Fork, sinon tu ne pourras rien pousser !
-
Initialise une
ArrayListdeHeronomméeheroes -
Ajoute à la liste
heroesles nouvelles instances deHerosuivantes :
// name: Black Widow, age: 34
// name: Captain America, age: 100
// name: Vision, age: 3
// name: Iron Man, age: 48
// name: Scarlet Witch, age: 29
// name: Thor, age: 1500
// name: Hulk, age: 49
// name: Doctor Strange, age: 42
-
C'est l'anniversaire de Thor, il a maintenant 1501 ans ! Modifie son instance dans la liste
-
Mélange la liste de façon aléatoire grâce à une méthode existante (elle est dans une ressource d'une étape précédente)
-
Ne garde que la première moitié de la liste grâce à une méthode existante (elle est dans une ressource d'une étape précédente)
-
Avec une boucle, affiche dans le terminal le nom des héros encore en vie
Exemple de résultat possible lors de l'exécution de Thanos :
$ Scarlet Witch
$ Spider-Man
$ Hulk
$ Iron Man
Critères de validation
- Le dépôt GitHub contient bien les fichiers
Hero.javaetThanos.java - La classe
Thanoscontient bien uneArrayListnomméeheroes, avec les 8 instances deHerodemandées. - La liste est bien mélangée aléatoirement grâce à une méthode
- La liste voit bien son nombre de héros réduit de moitié grâce à une méthode
- La classe
Thanosse compile sans erreur et affiche dans le terminal un résultat proche de celui présenté précédemment (les noms des héros doivent varier selon l’exécution)