Java
Programming
List Creation
Coding Tutorial
Data Structures

How to make a new List in Java

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

In Java, you do not instantiate the List interface directly. You create an object from a class that implements List, such as ArrayList or LinkedList, and usually store it in a List variable so your code depends on the interface rather than one concrete implementation.

The Most Common Pattern: ArrayList

For most cases, the default answer is ArrayList.

java
1import java.util.ArrayList;
2import java.util.List;
3
4public class Main {
5    public static void main(String[] args) {
6        List<String> fruits = new ArrayList<>();
7        fruits.add("Apple");
8        fruits.add("Banana");
9        fruits.add("Cherry");
10
11        System.out.println(fruits);
12    }
13}

This is the common idiom:

  • 'List<String> for the variable type'
  • 'new ArrayList<>() for the actual implementation'

That gives you flexibility to change the implementation later without changing most of the code that uses the list.

Why Use the Interface Type?

Writing List<String> fruits = new ArrayList<>(); is usually better than writing ArrayList<String> fruits = new ArrayList<>(); unless you need ArrayList-specific behavior.

The interface-based declaration makes the code less coupled to one implementation. If later you want LinkedList or another List implementation, fewer parts of the code need to change.

LinkedList Is Another Option

LinkedList also implements List.

java
1import java.util.LinkedList;
2import java.util.List;
3
4public class Main {
5    public static void main(String[] args) {
6        List<String> cities = new LinkedList<>();
7        cities.add("New York");
8        cities.add("London");
9        cities.add("Sydney");
10
11        System.out.println(cities);
12    }
13}

It is often chosen when insertion and removal patterns matter more than fast indexed access, although in everyday application code ArrayList remains the more common default.

Create a List with Initial Values

Sometimes you want a list that starts with known elements. One traditional approach is:

java
1import java.util.ArrayList;
2import java.util.Arrays;
3import java.util.List;
4
5List<String> colors = new ArrayList<>(Arrays.asList("red", "green", "blue"));
6System.out.println(colors);

In modern Java, List.of(...) is often cleaner when you want an immutable list.

java
1import java.util.List;
2
3List<String> colors = List.of("red", "green", "blue");
4System.out.println(colors);

The key difference is mutability. List.of(...) creates an unmodifiable list, so add() and remove() are not allowed on it.

Mutable Versus Immutable Lists

This distinction matters a lot:

  • 'new ArrayList<>() gives you a mutable list'
  • 'List.of(...) gives you an unmodifiable list'

If you write:

java
List<String> names = List.of("Ana", "Ben");
names.add("Cai");

you will get an exception at runtime. So choose the creation style based on whether the list should change after creation.

Copying an Existing List

Another common way to make a new list is to copy an existing one into a mutable implementation.

java
1import java.util.ArrayList;
2import java.util.List;
3
4List<String> original = List.of("red", "green", "blue");
5List<String> copy = new ArrayList<>(original);
6
7copy.add("yellow");
8System.out.println(copy);

This is useful when you want the convenience of List.of(...) as input but still need a list you can modify later.

Choose the Implementation by Use Case

A simple rule works well:

  • use ArrayList by default
  • use LinkedList only when you have a reason
  • use List.of(...) when you want a small fixed list

That keeps code readable and avoids premature optimization. Many Java programs work perfectly well with ArrayList unless profiling or a special usage pattern suggests otherwise.

Common Pitfalls

The most common mistake is trying to instantiate List directly with new List<>(), which does not work because List is an interface. Another is forgetting that List.of(...) returns an unmodifiable list and then trying to call add() or remove(). Developers also sometimes declare variables with a concrete implementation type when the interface type would make the code more flexible for no extra cost.

Summary

  • Create a List by instantiating an implementing class such as ArrayList.
  • The usual pattern is List<Type> list = new ArrayList<>();.
  • Use LinkedList only when its behavior is a better fit for the problem.
  • Use List.of(...) for concise unmodifiable lists.
  • Prefer the List interface in variable declarations unless you need implementation-specific features.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.