W3docs

Interface List en Java

Collections ordonnées et accessibles par index en Java avec l'interface List et ses opérations principales.

List<E> est Collection<E> plus deux engagements supplémentaires : les éléments ont un ordre défini, et cet ordre est adressable par un index entier. Une fois que vous disposez d'un ordre et d'un index, toute une classe de méthodes devient pertinente — get(i), set(i, x), indexOf(x), subList(from, to), tri, itération en sens inverse. Ce chapitre parcourt le contrat ; les implémentations (ArrayList, LinkedList, Vector) viennent immédiatement après avec leurs propres compromis de performance.

Ce que signifie « ordonné » ici

« Ordonné » sur une List signifie que l'ordre d'insertion est préservé — l'index 0 est le premier élément que vous avez inséré, l'index size() - 1 est le dernier, et l'ajout d'un nouvel élément à la fin ne déplace rien. Ce n'est pas « trié » — une liste conserve l'ordre que vous produisez. Si vous souhaitez une itération triée, vous appelez soit Collections.sort(list) (qui mute), soit vous utilisez TreeSet / TreeMap dès le départ. Ne confondez pas les deux.

Les doublons sont autorisés. [1, 1, 2, 1] est une List<Integer> parfaitement légale.

Les méthodes que List ajoute à Collection

Tout ce que Collection déclare est toujours là — add, remove, contains, size, etc. List ajoute ensuite des opérations positionnelles et sensibles à l'ordre :

Accès positionnel

  • E get(int index) — élément à index.
  • E set(int index, E element) — remplacement, renvoyant l'ancienne valeur.
  • void add(int index, E element) — insertion (décale les éléments suivants vers la droite).
  • E remove(int index) — suppression par position (renvoie l'élément supprimé). Notez la surcharge avec Objectlist.remove(1) appelle la version int ; list.remove(Integer.valueOf(1)) appelle la version Object.

Recherche

  • int indexOf(Object o) — première occurrence, ou -1.
  • int lastIndexOf(Object o) — dernière occurrence, ou -1.

Sous-vues et itération

  • List<E> subList(int fromIndex, int toIndex) — une vue en direct d'une plage. La modifier modifie la liste de support (et inversement). Semi-ouverte : [from, to).
  • ListIterator<E> listIterator() / listIterator(int index) — itérateur qui peut également se déplacer en sens inverse, obtenir l'index courant, et set / add au niveau du curseur. Le chapitre ListIterator le couvre.

Mutation en masse liée à l'ordre

  • default void replaceAll(UnaryOperator<E> op) — applique op à chaque élément en place.
  • default void sort(Comparator<? super E> c) — trie la liste à l'aide de c (ou de l'ordre naturel si null).
  • boolean addAll(int index, Collection<? extends E> c) — insère toute une collection à index.

Fabriques (Java 9+)

  • List.of(...) — une liste non modifiable contenant les éléments donnés. Compacte, sans allocation pour les petites tailles.
  • List.copyOf(Collection) — un instantané non modifiable d'une autre collection.

L'égalité sur List est sensible à l'ordre

Deux listes sont égales si et seulement si elles ont la même taille, dans le même ordre, avec des éléments égaux à chaque index. List.of(1, 2) n'est pas égal à List.of(2, 1), même s'ils l'auraient été en tant que Set. C'est une règle absolue du contrat List — si vous comparez deux listes et obtenez false alors que vous ne « devriez » pas, vérifiez l'ordre en premier.

subList est une vue, pas une copie

Cela prend presque chaque apprenant par surprise une fois :

List<Integer> xs = new ArrayList<>(List.of(0, 1, 2, 3, 4, 5));
List<Integer> middle = xs.subList(2, 5);    // [2, 3, 4]
middle.set(0, 99);
System.out.println(xs);          // [0, 1, 99, 3, 4, 5]   — xs changed!
middle.clear();
System.out.println(xs);          // [0, 1, 5]            — gone from xs

subList renvoie une fenêtre en direct. Les lectures et les écritures passent par la liste de support. C'est extrêmement utile pour les algorithmes en place — effacer une plage, trier une plage, insérer une plage — mais cela signifie également que vous ne pouvez pas conserver une référence subList et muter ensuite le parent par tout autre chemin. La Javadoc indique que les modifications structurelles de la liste de support en dehors de la sous-liste « rendent indéfini » le comportement de la sous-liste. En pratique, ConcurrentModificationException au prochain appel.

Si vous souhaitez une tranche indépendante, copiez-la : new ArrayList<>(xs.subList(2, 5)).

Les deux surcharges de remove

Un bug courant :

List<Integer> nums = new ArrayList<>(List.of(10, 20, 30));
nums.remove(1);                       // removes index 1 → [10, 30]
nums.remove(Integer.valueOf(10));     // removes the value 10 → [30]

La surcharge int l'emporte car int est plus spécifique que Integer. Si vous voulez dire « supprimer la valeur 10 », encadrez-la explicitement. C'est l'un des rares endroits dans le langage où les règles d'autoboxing et la résolution des surcharges entrent activement en conflit.

Tri en place

list.sort(comparator) mute la liste. Passez null pour utiliser l'ordre naturel des éléments (leur Comparable) ; passez un Comparator sinon. C'est la forme moderne — Collections.sort(list) fonctionne toujours et est identique, mais list.sort(...) est la méthode List par défaut :

List<String> names = new ArrayList<>(List.of("Linus", "Ada", "Grace"));
names.sort(null);                              // natural: ["Ada", "Grace", "Linus"]
names.sort(Comparator.comparingInt(String::length));  // shortest first

Le chapitre Comparable / Comparator plus loin dans cette partie est le livre de règles concernant ce que signifie null et comment construire des comparateurs pour vos propres types.

Fabriques immuables : quand add lève une exception

List.of(...), List.copyOf(...) et les listes renvoyées par Collectors.toUnmodifiableList() sont non modifiables. Elles rejettent chaque appel mutant avec UnsupportedOperationException. Elles rejettent également les éléments null. Elles sont idéales pour des données en lecture seule partagées largement :

List<String> CONSTANTS = List.of("red", "green", "blue");
CONSTANTS.add("yellow");    // throws UnsupportedOperationException

Si vous pensez vouloir muter ultérieurement, commencez avec new ArrayList<>(List.of(...)).

Un exemple concret : toutes les méthodes spécifiques à List

Le programme ci-dessous exerce les méthodes que List ajoute par rapport à Collection. Observez la propagation de la mutation via subList, le piège de surcharge, et la différence entre sort et replaceAll.

java— editable, runs on the server

Quelques points à retenir à partir de la sortie :

  • remove(1) a supprimé 20 (la valeur à l'index 1) ; remove(Integer.valueOf(10)) a supprimé 10 par valeur. Même nom de méthode, deux travaux différents selon le type statique de l'argument.
  • Après mid.clear(), la liste parente est [0, 1, 5]. La vue était la plage — l'effacer a supprimé ces éléments du tableau de support.
  • replaceAll conserve la même longueur de liste et réécrit chaque élément en place ; sort réarrange ce qui s'y trouve déjà. Ils se composent bien.

Prochaine étape

Vous connaissez maintenant le contrat List — ce qui est garanti, ce qui mute quoi, et où se trouvent les pièges. Il est temps de rencontrer l'implémentation que vous utiliserez 90 % du temps : ArrayList, adossée à un tableau redimensionnable. Même contrat, caractéristiques de performance spécifiques, et quelques extras qui lui sont propres.

Pratique

Pratique
`xs` est `new ArrayList<>(List.of(10, 20, 30, 40))`. Vous appelez `xs.subList(1, 3).clear()`. Qu'est-ce que `xs` ensuite ?
`xs` est `new ArrayList<>(List.of(10, 20, 30, 40))`. Vous appelez `xs.subList(1, 3).clear()`. Qu'est-ce que `xs` ensuite ?
Was this page helpful?