Java

Java List.of(...) Use Cases

List.of(...) is a compact way to create a small immutable list in Java. It is great for constants, examples, test inputs, and quick return values, but it has a few edges worth remembering.

Version Support

List.of(...) was added in Java 9.

List<Integer> numbers = List.of(1, 2, 3);

Stream.toList() was added later in Java 16.

List<Integer> copy = numbers.stream().toList();

If you are on Java 8, use Arrays.asList(...), Collections.unmodifiableList(...), or an ArrayList depending on whether you need mutability.

Basic Use

List<Integer> a = List.of(1, 2);

This creates an immutable list containing 1 and 2.

You cannot add, remove, or replace elements:

a.add(3); // throws UnsupportedOperationException

Use this when the list is meant to be a fixed value.

List.of(a) Creates A Nested List

This line does not copy the elements from a:

List<Integer> a = List.of(1, 2);
var c = List.of(a);

The type of c is:

List<List<Integer>>

The value is:

[[1, 2]]

That means List.of(a) creates a list with one element, and that one element is the list a.

Use this when you intentionally want a list of lists.

Two Lists Inside One Outer List

If you write:

List<Integer> a = List.of(1, 2);
List<Integer> b = List.of(3, 4);

var d = List.of(a.stream().toList(), b.stream().toList());

The type of d is:

List<List<Integer>>

The value is:

[[1, 2], [3, 4]]

This is useful when you want to preserve the two lists as separate groups.

For Java 10 to Java 15, replace stream().toList() with:

List.copyOf(a)

Example:

var d = List.of(List.copyOf(a), List.copyOf(b));

For Java 9 specifically, use:

var d = List.of(
    Collections.unmodifiableList(new ArrayList<>(a)),
    Collections.unmodifiableList(new ArrayList<>(b))
);

Combining Two Lists Into One List

If the goal is one flat list, do not use List.of(a, b). That gives a nested list:

var nested = List.of(a, b); // [[1, 2], [3, 4]]

Instead, create a mutable copy and add the other list:

List<Integer> e = List.of(3, 4);
List<Integer> f = new ArrayList<>(e);
f.addAll(a);

Now f is:

[3, 4, 1, 2]

If you want a first:

List<Integer> f = new ArrayList<>(a);
f.addAll(e);

Result:

[1, 2, 3, 4]

Stream-Based Merge

In Java 16+, you can merge lists with streams:

List<Integer> merged = Stream.concat(a.stream(), b.stream()).toList();

This returns an unmodifiable list.

Remember the imports:

import java.util.stream.Stream;

If you need a mutable list:

List<Integer> merged = Stream.concat(a.stream(), b.stream())
    .collect(Collectors.toCollection(ArrayList::new));

Imports:

import java.util.ArrayList;
import java.util.stream.Collectors;
import java.util.stream.Stream;

Nulls Are Not Allowed

List.of(...) rejects null values:

List.of(1, null); // throws NullPointerException

This is different from new ArrayList<>(), which can hold null.

Quick Decision Table

NeedUse
Small immutable listList.of(1, 2, 3)
List containing another listList.of(a)
Two lists as two groupsList.of(a, b)
One combined mutable listnew ArrayList<>(a); addAll(b);
One combined immutable list in Java 16+Stream.concat(a.stream(), b.stream()).toList()
Defensive immutable copy in Java 10+List.copyOf(existingList)

Takeaways