List Java - choisir entre ArrayList et LinkedList

Alfred Jacques .

19 septembre 2026

Tableau comparatif des différences entre ArrayList et LinkedList en Java. L'ArrayList utilise un tableau dynamique, la LinkedList une liste doublement chaînée.

Une liste de tâches, des résultats d’API ou des produits à afficher dans l’ordre ont un point commun : les éléments doivent rester ordonnés et facilement accessibles. En Java, l’interface List répond à ce besoin avec un ensemble de méthodes cohérent, mais le choix de son implémentation influence directement les performances, la mutabilité et la sécurité du code. Je présente ici les différences entre ArrayList, LinkedList et les autres options utiles, avec des exemples directement réutilisables.

Les choix essentiels pour utiliser une liste Java sans mauvaise surprise

  • List conserve l’ordre, accepte généralement les doublons et utilise des index commençant à 0.
  • ArrayList est le choix par défaut pour la plupart des applications.
  • LinkedList devient intéressante surtout pour les ajouts et suppressions fréquents aux extrémités.
  • List.of() et List.copyOf() créent des listes non modifiables.
  • Les listes ne sont pas automatiquement thread-safe et certaines opérations peuvent lever UnsupportedOperationException.

Ce que garantit vraiment l’interface List

List est une interface, pas une structure de données concrète. Elle décrit le comportement attendu d’une collection ordonnée : accès par position, recherche d’un élément, insertion à un index donné et conservation de l’ordre d’ajout.

Les index commencent à 0. Le premier élément se lit donc avec get(0), tandis que le dernier se trouve à get(size() - 1). Une liste peut généralement contenir plusieurs fois la même valeur, contrairement à un Set qui sert plutôt à garantir l’unicité.

List villes = new ArrayList<>();

villes.add("Paris");
villes.add("Lyon");
villes.add(1, "Nantes");

String premiereVille = villes.get(0);

Dans cet exemple, Nantes est insérée à l’index 1, ce qui décale Lyon vers la position suivante. C’est précisément cette maîtrise de la position qui rend List adaptée aux résultats paginés, aux étapes d’un processus ou à une séquence d’événements.

La bonne pratique consiste à déclarer la variable avec le type de l’interface et à choisir l’implémentation uniquement lors de la création. Je garde ainsi la liberté de remplacer ArrayList par une autre solution sans modifier les méthodes qui utilisent la collection.

List utilisateurs = new ArrayList<>();

ArrayList ou LinkedList pour quel usage

Les deux implémentations générales les plus connues sont ArrayList et LinkedList. Elles offrent toutes deux les opérations de List, mais leur organisation interne n’est pas la même, ce qui change le coût de certaines opérations.

Critère ArrayList LinkedList
Accès par index Très rapide, généralement en temps constant Plus lent, car la liste doit parcourir les nœuds
Ajout en fin Rapide en moyenne Rapide
Insertion au milieu Les éléments doivent être décalés Le déplacement jusqu’au nœud reste coûteux
Suppression aux extrémités Correcte en fin, moins adaptée au début Très adaptée au début et à la fin
Usage mémoire Plus compact Plus élevé à cause des liens entre nœuds

ArrayList est mon choix par défaut. Elle exploite un tableau redimensionnable, offre un accès direct efficace et fonctionne très bien quand le programme lit souvent les éléments ou parcourt la collection de bout en bout.

LinkedList a du sens lorsque le comportement ressemble davantage à celui d’une file ou d’une deque, avec des ajouts et suppressions fréquents au début ou à la fin. Elle n’est pas automatiquement plus rapide pour une insertion au milieu : trouver la position peut déjà demander un parcours coûteux.

Une erreur fréquente consiste à choisir LinkedList dès qu’une insertion est prévue. Dans une application classique, la fréquence des lectures et la taille réelle de la collection comptent souvent davantage que l’opération théorique d’insertion.

Créer une liste modifiable, fixe ou non modifiable

Le mot « liste » ne suffit pas à déterminer si l’on peut ajouter ou supprimer des éléments. Les méthodes de modification sont parfois optionnelles, et certaines fabriques renvoient volontairement une collection protégée.

Une liste modifiable

List langages = new ArrayList<>();
langages.add("Java");
langages.add("Kotlin");
langages.remove("Kotlin");

Cette forme convient lorsqu’une collection doit évoluer pendant l’exécution. Pour initialiser une liste à partir d’autres valeurs tout en conservant la possibilité de la modifier, je préfère créer explicitement une copie.

List sources = List.of("API", "Base de données");
List copie = new ArrayList<>(sources);
copie.add("Cache");

Les fabriques pratiques de Java

List.of() crée une liste non modifiable. Elle refuse également les valeurs null. C’est une excellente solution pour transmettre une configuration constante ou retourner quelques valeurs sans exposer une collection modifiable.

List codes = List.of(200, 201, 204);
// codes.add(500); déclenche UnsupportedOperationException

List.copyOf() produit aussi une liste non modifiable à partir d’une collection existante. À l’inverse, Arrays.asList() crée une liste de taille fixe liée au tableau d’origine : set() est possible, mais add() et remove() ne le sont pas.

String[] tableau = {"A", "B"};
List tailleFixe = Arrays.asList(tableau);

tailleFixe.set(0, "X");
 // tailleFixe.add("C") provoquerait une exception

Cette distinction évite beaucoup de bugs. Avant de modifier une liste reçue en paramètre, je vérifie toujours si le contrat de la méthode garantit réellement qu’elle est mutable.

Les opérations utiles au quotidien

Une liste devient intéressante lorsqu’elle simplifie le traitement des données. Les méthodes contains, indexOf, removeIf, sort et subList couvrent une grande partie des besoins courants.

List notes = new ArrayList<>(List.of(12, 8, 17, 9));

notes.removeIf(note -> note < 10);
notes.sort(Comparator.reverseOrder());

for (Integer note : notes) {
    System.out.println(note);
}

Pour parcourir les éléments, la boucle améliorée ou la méthode forEach sont généralement plus lisibles qu’un accès répété par index. Ce point est particulièrement important avec LinkedList, car une succession de get(i) peut entraîner un parcours inutile de la structure.

notes.forEach(note -> System.out.println("Note : " + note));

subList(from, to) renvoie une vue sur la liste d’origine, et non une copie indépendante. Une modification de la sous-liste peut donc modifier la collection principale. Pour obtenir une copie sûre, je l’encapsule dans un nouveau constructeur.

List extrait = new ArrayList<>(notes.subList(0, 2));

Depuis Java 21, les listes disposent aussi d’opérations liées à l’ordre séquentiel comme getFirst(), getLast() et reversed(). Cette dernière renvoie une vue inversée, pas nécessairement une nouvelle liste, ce qui mérite de la prudence si la collection est ensuite modifiée.

Les erreurs qui reviennent le plus souvent

Confondre suppression par index et suppression par valeur

Avec une liste d’entiers, remove(1) supprime l’élément situé à l’index 1, et non la valeur 1. Pour supprimer la valeur, il faut fournir un objet Integer.

List nombres = new ArrayList<>(List.of(10, 20, 30));

nombres.remove(1);                 // supprime 20
nombres.remove(Integer.valueOf(30)); // supprime la valeur 30

C’est un détail de surcharge très discret, mais il peut produire des résultats incorrects sans provoquer d’erreur de compilation. Je recommande de rendre l’intention explicite dès que le type de la liste est numérique.

Modifier une liste pendant son parcours

Supprimer directement un élément dans une boucle for-each peut déclencher une ConcurrentModificationException. La méthode removeIf est souvent plus claire et gère précisément ce cas.

utilisateurs.removeIf(nom -> nom.isBlank());

Si un traitement plus complexe est nécessaire, un Iterator permet une suppression contrôlée. Dans tous les cas, il faut distinguer une modification par le même thread pendant l’itération d’un vrai problème de concurrence entre plusieurs threads.

Lire aussi : Java Vector - Quand l'utiliser (ou l'éviter) en 2024 ?

Oublier la sécurité des threads

ArrayList et LinkedList ne sont pas thread-safe. Pour plusieurs lectures et très peu d’écritures, CopyOnWriteArrayList peut être pertinente, car les itérations travaillent sur une copie stable, mais chaque modification coûte davantage.

Collections.synchronizedList() fournit une enveloppe synchronisée, mais l’itération doit aussi être protégée par un bloc synchronized. Pour ma part, je ne choisis une collection concurrente qu’après avoir identifié le partage réel entre threads, car la synchronisation ajoute un coût qui n’apporte rien dans un code strictement local.

Le réflexe simple pour choisir la bonne collection

Dans la majorité des projets, je commence avec List et ArrayList<>. Cette combinaison offre une API claire, un accès rapide par index et un comportement prévisible pour les parcours, les tris et les recherches.

Je passe à LinkedList seulement si le profil d’utilisation justifie réellement des opérations fréquentes aux deux extrémités. Pour des valeurs constantes, List.of ou List.copyOf rendent l’intention plus sûre et évitent qu’une méthode modifie accidentellement des données partagées.

Le meilleur choix ne dépend donc pas du nom de la classe, mais de trois questions concrètes : la liste doit-elle être modifiable, l’accès par index est-il fréquent et plusieurs threads l’utilisent-ils ? Une fois ces réponses établies, l’implémentation appropriée devient généralement évidente.

Questions fréquentes

ArrayList convient par défaut lorsque les accès par index, les lectures et les parcours sont fréquents. LinkedList devient pertinente surtout pour les ajouts et suppressions répétés au début ou à la fin, mais son accès par index est plus lent et son usage mémoire plus élevé.
List.of et List.copyOf produisent des listes non modifiables, et List.of refuse les valeurs null. Pour obtenir une copie modifiable, utilisez new ArrayList<>(sources), puis ajoutez ou supprimez les éléments nécessaires.
Avec une liste d’entiers, remove(1) sélectionne la surcharge qui supprime l’élément situé à l’index 1. Pour supprimer la valeur 1, utilisez remove(Integer.valueOf(1)) afin de rendre l’intention explicite.
subList(from, to) renvoie une vue sur la liste d’origine, donc une modification de cette sous-liste peut modifier la collection principale. Pour obtenir une copie indépendante, créez-la avec new ArrayList<>(liste.subList(from, to)).
ArrayList et LinkedList ne sont pas thread-safe. CopyOnWriteArrayList convient surtout à plusieurs lectures et très peu d’écritures, tandis que Collections.synchronizedList nécessite aussi de protéger l’itération dans un bloc synchronized.
Évaluer l'article

Moyenne: 0.0 / 5 · 0 évaluations

Tags

list arraylist linkedlist mutabilité concurrence
Autor Alfred Jacques
Alfred Jacques
Je m'appelle Alfred Jacques et j'ai accumulé 12 ans d'expérience dans le domaine des technologies, en particulier dans les secteurs du web, de l'intelligence artificielle, des réseaux et de la sécurité. Mon intérêt pour ces sujets a débuté dès mon adolescence, lorsque j'ai découvert les possibilités infinies qu'offrent les nouvelles technologies. J'aime explorer les enjeux complexes de ces domaines et partager des informations claires et accessibles pour aider mes lecteurs à mieux comprendre les défis et les évolutions technologiques. Dans mes écrits, je m'efforce de fournir des analyses précises et à jour, en vérifiant mes sources et en comparant différentes perspectives. Je m'engage à simplifier des concepts parfois difficiles afin de rendre l'information utile et compréhensible pour tous. Que ce soit en suivant les dernières tendances ou en organisant mes connaissances de manière claire, je souhaite que mes articles soient une ressource précieuse pour ceux qui s'intéressent à la technologie et à ses implications dans notre quotidien.
Commentaires (0)
Ajouter un commentaire