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

Alfred Jacques .

7 juin 2026

Un développeur avec une ampoule "JAVA" sur un écran d'ordinateur, entouré de code binaire.

La classe Vector reste une brique utile pour lire, maintenir ou moderniser du code Java ancien, surtout quand la taille d’une liste varie et que la synchronisation fait partie du contrat. Derrière java vector, on parle d’un tableau dynamique qui garde des accès par indice, mais avec une gestion de capacité et un verrouillage intégrés. Je vais montrer ce que cela change concrètement, quelles méthodes comptent vraiment et pourquoi, dans la plupart des projets neufs, on lui préfère d’autres collections.

L’essentiel à retenir sur Vector en Java

  • Vector est une liste redimensionnable, mais aussi synchronisée à l’échelle des opérations élémentaires.
  • Sa taille et sa capacité sont deux notions différentes, et c’est souvent là que les confusions commencent.
  • ensureCapacity() sert à réserver de la place avant un remplissage massif, tandis que trimToSize() réduit l’empreinte mémoire.
  • Les méthodes historiques comme addElement() ou elementAt() existent encore, mais les méthodes de List sont généralement plus lisibles.
  • Pour du code neuf, ArrayList reste le choix par défaut si la synchronisation externe n’est pas nécessaire.
  • Si les lectures dominent très largement les modifications, CopyOnWriteArrayList peut être plus adapté.

Ce qu’est vraiment Vector en Java

Vector est une implémentation héritée de la collection List qui stocke des objets dans un tableau interne redimensionnable. En pratique, on l’utilise comme une liste indexée: on ajoute, on lit, on remplace et on supprime des éléments sans gérer soi-même la taille du tableau sous-jacent.

La différence importante avec beaucoup d’autres listes Java, c’est que Vector est synchronisé. La documentation Oracle le classe d’ailleurs parmi les implémentations héritées, et elle recommande ArrayList si vous n’avez pas besoin d’une structure thread-safe. Autrement dit, Vector n’est pas la référence moderne pour les nouveaux développements; il reste surtout présent pour la compatibilité et pour le code qui a traversé plusieurs générations de Java.

On retrouve aussi dans cette classe des méthodes plus anciennes, héritées de l’époque pré-collections, comme addElement(), elementAt() ou firstElement(). Elles fonctionnent encore, mais elles signalent souvent une base de code qui mérite d’être relue avec un œil de migration. C’est précisément pour cela qu’il faut comprendre sa mécanique interne, pas seulement sa syntaxe.

Une fois cette base posée, le point suivant à éclaircir est presque toujours le même: comment sa capacité évolue réellement quand la liste grossit.

Diagramme des structures de tableaux dynamiques en Java : Vector, ArrayList, CopyOnWriteArrayList, LinkedList. Le Vector est une version synchronisée.

Comment sa capacité évolue quand on ajoute des éléments

Avec Vector, il faut distinguer la taille de la capacité. La taille correspond au nombre d’éléments réellement présents; la capacité correspond à la place réservée dans le tableau interne. La documentation officielle indique qu’un Vector vide démarre avec une capacité par défaut de 10, puis grossit automatiquement.

Le comportement de croissance dépend de capacityIncrement. Si cet incrément vaut 0 ou une valeur négative, la capacité double lorsqu’elle doit augmenter. Si l’incrément est positif, la capacité progresse par paliers fixes. En pratique, cela veut dire que deux vecteurs de même taille peuvent avoir des empreintes mémoire différentes selon la façon dont ils ont été alimentés.

Méthode Rôle Quand je l’utilise
ensureCapacity(int) Réserve de la place avant un futur remplissage Avant d’importer beaucoup d’éléments d’un coup
trimToSize() Ramène la capacité à la taille courante Quand la liste est stabilisée et ne devrait plus grossir
setSize(int) Agrandit avec des null ou tronque la fin Surtout pour compatibilité avec du code ancien

Je traite trimToSize() avec prudence: le gain mémoire peut être réel si la liste se fige, mais si elle repart souvent à la hausse, vous payez ensuite des réallocations supplémentaires. C’est un bon exemple d’optimisation qui n’a de sens que si le profil d’usage est clair. Maintenant qu’on sait comment la mémoire bouge, il faut regarder les méthodes que l’on emploie vraiment au quotidien.

Les méthodes que j’emploie vraiment

Dans du code courant, je m’appuie d’abord sur les opérations de List: add(), get(), set(), remove() et size(). Elles sont plus lisibles, plus cohérentes avec le reste de l’écosystème Java et plus faciles à faire évoluer que les vieux noms spécifiques à Vector.

Vector noms = new Vector<>();
noms.add("Alice");
noms.add("Benoît");
noms.add("Chloé");

String premier = noms.get(0);
noms.set(1, "Bruno");
noms.remove("Chloé");

for (String nom : noms) {
    System.out.println(nom);
}

Les méthodes firstElement() et lastElement() restent utiles pour le code hérité, mais dans un nouveau code je préfère get(0) et get(size() - 1). C’est plus uniforme et cela évite de mélanger des conventions anciennes avec des APIs modernes.

Le point le plus sous-estimé concerne le parcours. iterator() et listIterator() sont fail-fast: si la structure change après la création de l’itérateur, ils lèvent généralement une ConcurrentModificationException sur une base best-effort. En revanche, elements() renvoie une Enumeration historique qui n’est pas fail-fast et dont le résultat devient indéfini si la liste est modifiée pendant l’énumération.

Enumeration e = noms.elements();
while (e.hasMoreElements()) {
    System.out.println(e.nextElement());
}

Je réserve ce type de parcours à la maintenance de code ancien. Pour tout le reste, je passe par les boucles for-each ou par les itérateurs classiques. À partir de là, la vraie question n’est plus “comment l’utiliser”, mais “quand vaut-il encore la peine de l’utiliser”.

Quand Vector reste pertinent et quand je l’éviterais

Vector a encore sa place dans trois cas assez concrets: quand une API héritée vous le retourne déjà, quand vous devez conserver un comportement strictement compatible avec un vieux module, ou quand vous voulez une liste synchronisée sans repenser immédiatement toute l’architecture autour. Dans ce genre de contexte, le coût d’une migration peut être supérieur au bénéfice immédiat.

En revanche, pour un projet neuf, je l’éviterais presque toujours. La synchronisation intégrée a un coût, et surtout elle peut donner une fausse impression de sécurité: des opérations simples sont bien protégées, mais une logique composée de plusieurs étapes ne devient pas automatiquement atomique pour autant. Si votre code lit, teste puis modifie, vous avez souvent besoin d’un verrou plus large que celui d’une méthode isolée.

Autre point pratique: si vous cherchez une pile, Vector n’est plus le réflexe à garder. La classe Stack hérite historiquement de Vector, mais dans le Java moderne on pense plus volontiers à une structure dédiée comme Deque selon le besoin. Le vieux couple Vector/Stack dit surtout quelque chose sur l’âge du code, pas sur sa pertinence actuelle.

Cette différence entre héritage et choix moderne devient encore plus claire quand on compare Vector aux alternatives réellement utilisées aujourd’hui.

Comparer Vector, ArrayList et les alternatives synchronisées

Le guide des collections d’Oracle place Vector parmi les implémentations héritées, tandis que ArrayList y est présenté comme l’implémentation générale la plus équilibrée de List. C’est un bon résumé de la situation actuelle: Vector existe encore, mais il n’est plus le choix naturel par défaut.

Critère Vector ArrayList Collections.synchronizedList(new ArrayList<>()) CopyOnWriteArrayList
Synchronisation Intégrée, méthode par méthode Non Oui, via wrapper externe Oui, avec copie à chaque mutation
Meilleur scénario Compatibilité et code ancien Usage général, mono-thread ou synchronisation externe Liste classique à protéger simplement Beaucoup de lectures, peu d’écritures
Limite principale Verrouillage partout, héritage ancien Pas synchronisé Il faut verrouiller correctement l’accès global Les écritures coûtent cher
Ce que je recommande Seulement pour migrer ou conserver un contrat existant Par défaut Si vous voulez une liste simple mais thread-safe Si la traversée domine très largement

Si je devais résumer ma règle de décision, elle serait simple: ArrayList par défaut, synchronizedList si vous avez besoin d’un wrapper protecteur autour d’une liste classique, CopyOnWriteArrayList quand les lectures écrasent les écritures, et Vector uniquement pour la compatibilité ou la maintenance. Ce tri évite une erreur fréquente: choisir un type ancien parce qu’il “a l’air sûr” sans regarder le profil d’accès réel.

Une fois ce choix clarifié, la migration d’un ancien code devient beaucoup plus prévisible.

Migrer un ancien Vector sans casser le comportement

Quand je reprends une base qui utilise encore Vector, je procède par étapes plutôt que par remplacement brutal. L’idée n’est pas de “moderniser” pour moderniser, mais de conserver le comportement utile tout en retirant les dépendances inutiles à l’ancienne API.

  1. Je remplace les signatures publiques par List dès que possible, pour découpler le contrat du type concret.
  2. Je garde Vector en interne seulement si un composant externe l’exige encore.
  3. Je bascule vers ArrayList si la liste n’a pas besoin d’être synchronisée.
  4. Je choisis Collections.synchronizedList(...) si la liste doit rester simple mais protégée.
  5. Je teste les parcours, les nulls autorisés, la taille initiale et les points où le code s’appuyait implicitement sur setSize() ou sur les méthodes héritées.
List noms = new ArrayList<>(ancienVector);

// Si la synchronisation reste nécessaire
List nomsSecurises = Collections.synchronizedList(new ArrayList<>(ancienVector));

Le vrai piège, dans ce genre de migration, n’est pas la syntaxe. C’est l’hypothèse cachée: certains modules supposent que la taille peut changer par paliers, que les appels sont synchronisés implicitement ou que les méthodes historiques sont toujours là. C’est souvent là que se cachent les régressions. En gardant cette prudence, on évite de transformer une simple classe de collection en source de bugs difficile à diagnostiquer.

Ce que je garde en tête avant de choisir cette classe

Je considère Vector comme une classe utile à connaître, mais rarement comme un bon point de départ pour du code neuf. Il raconte l’histoire de Java, sa compatibilité ascendante et ses compromis de conception. Il peut encore dépanner, il peut encore être le bon choix pour un contrat ancien, mais il ne devrait pas être choisi par réflexe.
  • Si je maintiens un système ancien, je respecte d’abord le contrat existant.
  • Si j’écris un nouveau module, je pars presque toujours d’ArrayList.
  • Si la concurrence compte, je choisis la stratégie de synchronisation explicitement, au lieu de la laisser implicite.
  • Si les lectures dominent massivement, j’envisage CopyOnWriteArrayList avant de revenir à Vector.

Vector reste donc un excellent point d’entrée pour comprendre une partie importante de l’API Java, mais ce n’est pas l’outil que je mettrais au centre d’une architecture moderne. Pour un projet propre, je pars de la charge réelle, du niveau de concurrence et du rythme de modification, puis je choisis la collection qui répond à ce scénario, pas celle qui porte simplement le poids de l’héritage.

Questions fréquentes

Vector est une implémentation de la liste dynamique (tableau redimensionnable) en Java, similaire à ArrayList, mais avec une synchronisation intégrée sur chaque opération. Il est utile pour le code hérité ou lorsque la synchronisation est requise pour des opérations atomiques simples.
La différence majeure est la synchronisation. Vector est thread-safe car toutes ses méthodes sont synchronisées, tandis qu'ArrayList ne l'est pas. Cela rend ArrayList plus performant dans un environnement mono-thread, mais Vector plus sûr pour un accès concurrentiel simple.
Utilisez Vector principalement pour maintenir ou migrer du code ancien qui en dépend. Pour les nouveaux projets, ArrayList est le choix par défaut. Si une synchronisation est nécessaire, préférez Collections.synchronizedList() ou CopyOnWriteArrayList pour un contrôle plus fin et de meilleures performances dans des scénarios spécifiques.
Vector gère automatiquement sa capacité. Vous pouvez utiliser `ensureCapacity()` pour pré-allouer de l'espace avant d'ajouter de nombreux éléments, et `trimToSize()` pour réduire la capacité à la taille actuelle, libérant ainsi de la mémoire inutilisée.
Oui, si possible. Migrer vers ArrayList (si la synchronisation n'est pas nécessaire) ou d'autres alternatives thread-safe (comme Collections.synchronizedList ou CopyOnWriteArrayList) peut améliorer les performances et la clarté du code, tout en évitant les pièges de la synchronisation implicite de Vector.

Évaluer l'article

Moyenne: 0.0 / 5 · 0 évaluations

Tags

java vector java vector vs arraylist quand utiliser java vector vector en java synchronisation migrer vector java alternatives java vector
Autor Alfred Jacques
Alfred Jacques
Je m'appelle Alfred Jacques et je suis passionné par les technologies, en particulier dans les domaines du web, de l'intelligence artificielle, des réseaux et de la sécurité. Fort de plusieurs années d'expérience en tant qu'analyste de l'industrie, j'ai eu l'opportunité d'explorer en profondeur les tendances et les innovations qui façonnent notre monde numérique. Mon expertise se concentre sur l'analyse des systèmes de sécurité, l'impact de l'IA sur les entreprises et l'évolution des infrastructures web. Je m'efforce de simplifier des données complexes pour les rendre accessibles à tous, tout en garantissant une analyse objective et rigoureuse. Mon engagement envers mes lecteurs est de fournir des informations précises, à jour et fiables, afin de les aider à naviguer dans cet écosystème technologique en constante évolution.

Commentaires (0)

Ajouter un commentaire