Archives Wild Code School
Java Avancé

Collection 01 : List

Quête 1 sur 15

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.

↗
Oracle : Interface List
docs.oracle.com

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 :

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

↗
Wrapper Classes in Java
geeksforgeeks.org
↗
Oracle : Class ArrayList
docs.oracle.com

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.

java
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 :

java
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 :

java
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 :

java
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

java
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 !

java
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

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

java
// 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.

↗
How to shuffle an ArrayList
mkyong.com
↗
ArrayList subList method
geeksforgeeks.org
↗
W3Schools : Java ArrayList
w3schools.com

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

↗
Dépôt git
github.com

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 !

  1. Initialise une ArrayList de Hero nommée heroes

  2. Ajoute à la liste heroes les nouvelles instances de Hero suivantes :

java
// 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

  1. C'est l'anniversaire de Thor, il a maintenant 1501 ans ! Modifie son instance dans la liste

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

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

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

shell
$ Scarlet Witch
$ Spider-Man
$ Hulk
$ Iron Man

Critères de validation

  • Le dépôt GitHub contient bien les fichiers Hero.java et Thanos.java
  • La classe Thanos contient bien une ArrayList nommée heroes, avec les 8 instances de Hero demandé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 Thanos se 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)