Java Collections: List.
ArrayList, LinkedList and Vector explained.
You have heard of ArrayList. You have probably used it. But do you know when to use LinkedList instead — and why Vector exists at all? This article answers all three.
Java Collections SeriesPart 1: List — ArrayList, LinkedList, Vector (this article)
Part 2: Set — HashSet, LinkedHashSet, TreeSet (next week)
Part 3: Map — HashMap, LinkedHashMap, TreeMap (coming soon)
Part 4: Queue — Queue, Deque, PriorityQueue (coming soon)
The first time I used ArrayList in a real project, I just typed it in and moved on. It worked. I had no idea there were other types of List in Java, no idea why they existed, and no idea I was sometimes picking the wrong one. For a long time that was fine. Then I hit a situation where I needed to add items to the beginning of a list thousands of times in a loop. My ArrayList-based code was visibly slow. A teammate suggested LinkedList. The difference was immediate. That afternoon I finally understood why Java has more than one kind of List.
This is Part 1 of a four-part Java Collections series. Each part covers one Collection type in depth. This one is about List — what it is, which implementations exist, how they differ, and when to use each one.
The basics before the detail
A List in Java is an ordered collection that allows duplicate values. Ordered means the items stay in the sequence you added them. Item 1 stays first, item 2 stays second, and so on. You can access any item directly by its index number — just like an array.
The difference from an array is that a List grows automatically. You do not declare a size upfront. You just add items and the List handles the rest.
Java has three main List implementations: ArrayList, LinkedList, and Vector. They all store ordered data and allow duplicates. The difference is in how they store data internally — and that changes which operations are fast and which are slow.
Arraylist
The one you will use most
ArrayList stores its elements in a regular array behind the scenes. When that internal array gets full, Java creates a new bigger one and copies everything across. This is invisible to you — it just works.
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ArrayListExample {
public static void main(String[] args) {
List<String> cities = new ArrayList<>();
// add items
cities.add("Mumbai");
cities.add("Delhi");
cities.add("Bangalore");
cities.add("Mumbai"); // duplicates allowed
// read by index — very fast in ArrayList
System.out.println(cities.get(0)); // Mumbai
System.out.println(cities.get(2)); // Bangalore
// check size
System.out.println(cities.size()); // 4
// check if item exists
System.out.println(cities.contains("Delhi")); // true
// update an item
cities.set(1, "Chennai"); // replaces Delhi with Chennai
// remove by value
cities.remove("Mumbai"); // removes first occurrence only
// remove by index
cities.remove(0);
// sort alphabetically
Collections.sort(cities);
// loop through
for (String city : cities) {
System.out.println(city);
}
// find index of an item
System.out.println(cities.indexOf("Bangalore")); // 0 after sort
// clear everything
cities.clear();
System.out.println(cities.isEmpty()); // true
}
}What ArrayList is good at
Reading items by index is almost instant —
get(5000)is just as fast asget(0). Searching withcontains()and adding to the end withadd()are also fast. This is why ArrayList is the default choice for most situations.
Linkedlist
LinkedList does not use an internal array. Instead each item is stored in a separate node, and each node holds a reference to the next node and the previous node. It is like a chain — each link knows what comes before and after it.
This structure makes insertion and removal at the beginning or end extremely fast. You just update two references. No shifting required. But reading item number 5,000 by index is slow — LinkedList has to walk through the chain one node at a time to find it.
import java.util.LinkedList;
public class LinkedListExample {
public static void main(String[] args) {
LinkedList<String> tasks = new LinkedList<>();
// add to end — same as ArrayList
tasks.add("Write tests");
tasks.add("Review PR");
tasks.add("Fix bug");
// add to beginning — very fast in LinkedList
tasks.addFirst("Urgent: Deploy hotfix");
// add to end explicitly
tasks.addLast("Update documentation");
// peek — see first item without removing
System.out.println(tasks.peekFirst()); // Urgent: Deploy hotfix
// remove first item — very fast in LinkedList
tasks.removeFirst();
// remove last item — very fast in LinkedList
tasks.removeLast();
// loop through remaining tasks
for (String task : tasks) {
System.out.println(task);
}
// Write tests
// Review PR
// Fix bug
}
}Vector
Vector is the oldest List implementation in Java — it has been there since Java 1.0. It works almost identically to ArrayList, with one difference: every method in Vector is synchronized. This means it is safe to use across multiple threads without additional locking.
Get Deep Shah’s stories in your inbox
Join Medium for free to get updates from this writer.
The problem is that synchronization has a performance cost. Vector is measurably slower than ArrayList in single-threaded code. When Java 2 introduced the Collections framework and added ArrayList, most developers switched and never looked back.
import java.util.Vector;
public class VectorExample {
public static void main(String[] args) {
// Vector — thread-safe but slower than ArrayList
Vector<String> logs = new Vector<>();
logs.add("INFO: Server started");
logs.add("WARN: High memory usage");
logs.add("ERROR: Connection failed");
System.out.println(logs.get(0)); // INFO: Server started
System.out.println(logs.size()); // 3
// Vector-specific methods (legacy)
logs.addElement("DEBUG: Request received");
System.out.println(logs.firstElement()); // INFO: Server started
System.out.println(logs.lastElement()); // DEBUG: Request received
// For new code needing thread safety — use this instead:
// List<String> safeList = Collections.synchronizedList(new ArrayList<>());
}
}Should you use Vector in new code?
No. If you need thread safety, use
Collections.synchronizedList(new ArrayList<>())orCopyOnWriteArrayListinstead. Vector is kept in Java for backwards compatibility. You will encounter it in older codebases, so it is worth knowing — but do not write it in new projects.
Which one to pick
Use ArrayList when
You read items by index frequently. You add most items to the end. You do not know which to use — ArrayList is always the safe default. 90% of the time, this is the right choice.Use LinkedList when
You frequently add or remove items from the beginning or middle of the list. You are implementing a queue or a stack. You are doing many insertions in a loop and speed matters.Use Vector when
You are maintaining old Java code that already uses it. For new code, use Collections.synchronizedList(new ArrayList<>()) if you need thread safety.
My slow loop used ArrayList. Switching to LinkedList fixed the performance problem because I was adding thousands of items to the beginning — the one operation where LinkedList has a genuine advantage. If I had been reading items by index instead, ArrayList would have been faster.
That is the whole point. There is no universally best List. There is only the right one for what your code actually does.
Next in this series: Java Collections — Set
Next week: HashSet, LinkedHashSet and TreeSet explained. When to use each one, how they handle duplicates, and why TreeSet sorts your items automatically without you doing anything.
Resources
- ArrayList Java documentation — Oracle
- LinkedList Java documentation — Oracle
- Vector Java documentation — Oracle
- Java Collections tutorial — GeeksforGeeks
If this article helped you, consider clapping and following for more practical SDET content.
Connect
#Java #ArrayList #LinkedList #JavaCollections #JavaBeginner #CoreJava #Programming #SDET #LearnJava #SoftwareEngineering










