Java List, ArrayList and LinkedList

ArrayList and LinkedList both implement Java's List interface, but their storage differs.

Lesson 47 of 127Intermediate14 min read

ArrayList and LinkedList both implement Java's List interface, but their storage differs. ArrayList uses a resizable array; LinkedList uses linked nodes and also implements Deque. Choose based on the operations your program actually performs, not on a blanket claim that linked lists always insert faster.

Review the related foundation lesson when you need a prerequisite. The complete programs below use Java 17-compatible syntax.

Indexed list behavior

List describes an ordered sequence with indexed access. ArrayList stores references in a resizable backing array and is a common default for lists.

A List stores an ordered sequence with positions and generally permits equal elements. get and set access a position, add inserts and shifts later positions, and remove changes the sequence. Indices begin at zero. set replaces an existing element without increasing size; add inserts an element and increases size. Those contracts stay distinct even when the displayed values appear similar.

ArrayList operation costs

ArrayList indexed access is constant time. Appending is amortized constant time, while inserting near the front usually shifts many references.

ArrayList gives constant-time positional access and amortized constant-time append. Inserting or removing near the front usually requires shifting many references, which costs linear time. Its capacity may exceed size, but unused capacity is not part of the logical list. An initial capacity can avoid some growth allocations when the expected number of elements is known.

Linked traversal costs

LinkedList is a doubly linked list and also a Deque. Indexed access traverses links, so repeatedly using get(i) can make a loop unnecessarily expensive.

LinkedList must traverse nodes to reach an indexed position, so repeated get(i) traversal can turn a loop into quadratic work. Insertions through an iterator already positioned at a node can avoid shifting elements, but locating that position still costs traversal. LinkedList also stores node links and has different memory overhead. For end-based queue operations, ArrayDeque is often a sensible alternative to evaluate.

Insertion, removal overloads and subList views

Insertion through an already-positioned LinkedList iterator can avoid shifting elements. Searching for that position still costs traversal, so linked storage is not automatically faster for every insertion.

With List<Integer>, remove(1) selects the index overload and removes the second element. remove(Integer.valueOf(1)) selects the object overload and removes a matching value. A subList is normally a view backed by the original list, not an independent copy. Structural modifications outside that view can invalidate its expected usage, so copy it when the result needs its own lifetime.

Running the examples

Save name.java, compile it with javac --release 17 name.java, and run java name. Use each program's own public class name and filename.

How RouteListAndDeque produces its output

The list first contains Quarry and Meadow. add(1, "Canal") inserts Canal before Meadow, producing Quarry, Canal, Meadow. A new LinkedList copies those element references and is used through Deque. removeFirst returns Quarry from that separate queue. It does not remove Quarry from stops, because the queue has its own collection structure.

How ListPositions produces its output

set replaces write with test at index one, leaving two elements. add at that same index inserts review before test and shifts test to index two. The final sequence has three entries. The two operations use the same numeric argument but fulfill different contracts: replacement versus insertion.

How IntegerListRemoval produces its output

The literal one chooses remove(int), so the first call removes seven at index one. Passing an Integer chooses remove(Object), so the next call removes the first matching value one. One duplicate remains. This is compile-time overload selection, not a runtime guess about whether the programmer meant an index or a value.

Traverse according to the representation

An enhanced for loop is a sensible default when every list element is needed once. It uses iteration rather than requesting every numeric index separately, which avoids repeated indexed traversal on LinkedList. Use indices when their positions are genuinely part of the calculation and the representation supports that access pattern appropriately. For a queue workflow, choose operations such as addLast and removeFirst through Deque instead of disguising them as unrelated list indices. For practice, create an ArrayList and a LinkedList with the same elements, traverse both once with enhanced for and compare their output. Equal results do not prove equal internal costs.

Copies and list factories have different contracts

new ArrayList<>(source) creates a mutable collection structure whose later additions do not update source. Its elements remain references to the same objects, so changing a mutable element may still be visible through both lists. List.of creates an unmodifiable list and rejects null; Arrays.asList creates a fixed-size list backed by its object array and can allow replacement of existing elements. The declared List type does not distinguish these three contracts. When returning a list from an API, document whether callers may add, remove or replace entries and whether later changes to internal storage will appear in the returned value.

Java Summary

  • List describes an ordered sequence with indexed access. ArrayList stores references in a resizable backing array and is a common default for lists.
  • ArrayList indexed access is constant time. Appending is amortized constant time, while inserting near the front usually shifts many references.
  • LinkedList is a doubly linked list and also a Deque. Indexed access traverses links, so repeatedly using get(i) can make a loop unnecessarily expensive.
  • Insertion through an already-positioned LinkedList iterator can avoid shifting elements. Searching for that position still costs traversal, so linked storage is not automatically faster for every insertion.
  • Continue with Java exercises, Java quizzes and the Java study roadmap.

Java Examples

Each example shows the code, the output it produces and what each part does.

Example 1

Java List, ArrayList and LinkedList in a complete program

Java
public class RouteListAndDeque  {
    public static void main(String[] args)  {
        java.util.List<String> stops = new java.util.ArrayList<>();
        stops.add("Quarry");
        stops.add("Meadow");
        stops.add(1, "Canal");
        System.out.println(stops);
        java.util.Deque<String> queue = new java.util.LinkedList<>(stops);
        System.out.println(queue.removeFirst());
    }
}
Output
[Quarry, Canal, Meadow]
Quarry
Line-by-line explanation
  1. Line 7Evaluates stops and prints [Quarry, Canal, Meadow].
  2. Line 9Evaluates queue.removeFirst() and prints Quarry.
Example 2

Replacing is not inserting

Java
public class ListPositions  {
    public static void main(String[] args)  {
        java.util.List<String> tasks = new java.util.ArrayList<>(java.util.List.of("read", "write"));
        tasks.set(1, "test");
        tasks.add(1, "review");
        System.out.println(tasks);
        System.out.println(tasks.size());
    }
}
Output
[read, review, test]
3
Line-by-line explanation
  1. Line 6Evaluates tasks and prints [read, review, test].
  2. Line 7Evaluates tasks.size() and prints 3.
Example 3

Integer removal has two overloads

Java
public class IntegerListRemoval  {
    public static void main(String[] args)  {
        java.util.List<Integer> values = new java.util.ArrayList<>(java.util.List.of(1, 7, 1));
        values.remove(1);
        System.out.println(values);
        values.remove(Integer.valueOf(1));
        System.out.println(values);
    }
}
Output
[1, 1]
[1]
Line-by-line explanation
  1. Line 5Evaluates values and prints [1, 1].
  2. Line 7Evaluates values and prints [1].

Java FAQ

Does LinkedList always insert faster?

No. It can relink efficiently when an iterator already identifies the position, but indexed insertion first requires finding that position. ArrayList may also perform better in practice because of compact storage. Measure the actual workload instead of choosing from an oversimplified slogan.

Is subList an independent copy?

No, it is a backed view. Changes through supported view operations affect the parent list. For an independent structure, construct a new ArrayList from the subList. Referenced mutable elements remain shared unless you copy them separately.

How do I add to the start of a list efficiently?

arrayList.add(0, x) shifts every existing element along, which gets slow for long lists. If you add and remove at both ends often, use an ArrayDeque with addFirst and addLast, or a LinkedList. If you only need the final order reversed, add to the end and reverse once.

Why is a loop with get(i) slow on a LinkedList?

Each get(i) on a LinkedList walks from one end of the chain to position i, so calling it inside a loop over every index does quadratic work. Loop with an enhanced for or an iterator instead, which moves from node to node in a single pass.

Does new ArrayList<>(1000) create 1000 elements?

No. The number is the initial capacity, room reserved in the backing array, not the size. The list still has size() 0, and get(0) throws IndexOutOfBoundsException. Use it to avoid repeated resizing when you know roughly how many items you'll add.

Java Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Multiple choiceeasy

What does set(1, value) do?

Multiple choicemedium

Which call removes the Integer value one?

Java Quiz

2 questions to check what you learned.

  1. Why can a get(i) loop be slow on LinkedList?

    • Each indexed lookup may traverse nodes
    • LinkedList rejects loops
    • Every element is automatically sorted
  2. Which interface do both ArrayList and LinkedList implement?

    • List
    • Map
    • SortedSet