Java 9 – Immutable List of Objects Using List.of()
Java 9's List.of() factory method creates an unmodifiable list with a concise, one-line syntax. Earlier posts showed List.of() with primitive-wrapper and String elements. This post shows how to use it with a custom bean (POJO) — a more realistic use case for application development.
What Changes With Bean Objects?
The List.of() method works the same way regardless of the element type. The key difference is that bean objects are mutable — the list itself is immutable (you can't add or remove elements), but you can still call setters on the objects inside the list. This is an important distinction.
Product.java (Bean)
package com.java9r;
public class Product {
private String id;
private String name;
private double price;
public Product(String id, String name, double price) {
this.id = id;
this.name = name;
this.price = price;
}
public String getId() { return id; }
public String getName() { return name; }
public double getPrice() { return price; }
public void setId(String id) { this.id = id; }
public void setName(String name) { this.name = name; }
public void setPrice(double price) { this.price = price; }
@Override
public String toString() {
return String.format("Product{id='%s', name='%s', price=%.1f}", id, name, price);
}
}
ImmutableListWithBean.java
package com.java9r;
import java.util.List;
public class ImmutableListWithBean {
public static void main(String[] args) {
// Create an immutable list of Product objects
List<Product> products = List.of(
new Product("100", "Laptop", 75000.0),
new Product("101", "Smartphone", 25000.0),
new Product("102", "Tablet", 35000.0),
new Product("103", "Monitor", 15000.0),
new Product("104", "Keyboard", 2500.0)
);
System.out.println("Products List");
System.out.println("=============");
// Iterate using forEach with lambda
products.forEach(p -> {
System.out.println("Id: " + p.getId());
System.out.println("Name: " + p.getName());
System.out.println("Price: " + p.getPrice());
System.out.println("-------------------------");
});
System.out.println("Total products: " + products.size());
// The list is immutable — cannot add or remove
try {
products.add(new Product("105", "Mouse", 1500.0));
} catch (UnsupportedOperationException e) {
System.out.println("\nCannot add to immutable list: " + e.getClass().getSimpleName());
}
// But the objects inside are still mutable (if they have setters)
products.get(0).setPrice(70000.0);
System.out.println("Updated price: " + products.get(0).getPrice());
}
}
Output
Products List
=============
Id: 100
Name: Laptop
Price: 75000.0
-------------------------
Id: 101
Name: Smartphone
Price: 25000.0
-------------------------
Id: 102
Name: Tablet
Price: 35000.0
-------------------------
Id: 103
Name: Monitor
Price: 15000.0
-------------------------
Id: 104
Name: Keyboard
Price: 2500.0
-------------------------
Total products: 5
Cannot add to immutable list: UnsupportedOperationException
Updated price: 70000.0
Iterating – All Options
// 1. forEach with lambda
products.forEach(p -> System.out.println(p.getName()));
// 2. Enhanced for loop
for (Product p : products) {
System.out.println(p.getId() + ": " + p.getName());
}
// 3. Stream API
products.stream()
.filter(p -> p.getPrice() > 20000)
.map(Product::getName)
.forEach(System.out::println);
// 4. Stream with sorted
products.stream()
.sorted((a, b) -> Double.compare(a.getPrice(), b.getPrice()))
.forEach(System.out::println);
List.of() With Beans – Rules
| Operation | Allowed? | Result |
|---|---|---|
list.add(new Product(...)) |
No | UnsupportedOperationException |
list.remove(0) |
No | UnsupportedOperationException |
list.set(0, newProduct) |
No | UnsupportedOperationException |
list.get(0).setPrice(100) |
Yes | Modifies the bean object (list structure unchanged) |
list.forEach(...) |
Yes | Read-only iteration works fine |
list.contains(...) |
Yes | Works (uses equals()) |
Truly Immutable Objects
If you want a fully immutable list (where neither the list nor its elements can be changed), make the bean itself immutable using a record (Java 16+) or by making all fields final and removing setters:
// Java 16+ record — automatically immutable
record Product(String id, String name, double price) {}
List<Product> products = List.of(
new Product("100", "Laptop", 75000.0),
new Product("101", "Smartphone", 25000.0)
);
// products.get(0) has no setters — fully immutable
Summary
List.of() in Java 9 creates an unmodifiable list with a clean, one-line syntax that works with any object type, including custom beans. The list structure is immutable — you cannot add, remove, or replace elements. However, if the bean objects have setters, their fields can still be changed. To achieve full immutability, combine List.of() with immutable bean objects (using Java records or final-field-only classes). This pattern is ideal for read-only datasets like product catalogs, configuration tables, and test fixtures.
Comments