CoreJava Java9

Java 9 – Factory Methods for Immutable List: List.of() Explained

Java 9 – Factory Methods for Immutable List: List.of() Explained

Java 9 introduced List.of(), a convenient static factory method for creating immutable lists. Before Java 9, creating an unmodifiable list took three steps: create a mutable list, add elements, then call Collections.unmodifiableList(). With List.of(), you can do it in a single line.

This tutorial covers the List.of() factory method for both String elements and custom Java beans (POJOs), and explains the immutability rules that apply.

The Old Way vs the Java 9 Way


import java.util.Arrays;
import java.util.Collections;
import java.util.List;

// --- Before Java 9 ---
// Option 1: Arrays.asList() – fixed size but NOT fully immutable (set() still works)
List<String> old1 = Arrays.asList("Apple", "Mango", "Banana");
old1.set(0, "Orange");  // This WORKS with Arrays.asList()!

// Option 2: Collections.unmodifiableList() – truly immutable but verbose
List<String> old2 = Collections.unmodifiableList(Arrays.asList("Apple", "Mango"));

// --- Java 9 ---
// List.of() – concise, truly immutable, rejects null elements
List<String> fruits = List.of("Apple", "Mango", "Banana", "Grapes", "Orange");

Example 1: List.of() with Strings


package com.java9r;

import java.util.List;
import java.util.stream.Collectors;

/**
 * Java 9 – Immutable List.of() with String elements.
 */
public class Java9ImmutableListString {

    public static void main(String[] args) {

        // Create immutable list of product names
        var products = List.of(
            "Laptop", "Smartphone", "Tablet", "Monitor",
            "Keyboard", "Mouse", "Headphones", "Webcam"
        );

        System.out.println("Products: " + products);
        System.out.println("Size: " + products.size());
        System.out.println("Index 2: " + products.get(2));
        System.out.println("Contains 'Mouse': " + products.contains("Mouse"));

        // Iterate using for-each
        System.out.println("\nAll products:");
        for (var product : products) {
            System.out.println("  - " + product);
        }

        // Use Stream API to filter
        System.out.println("\nProducts with 'a' in name:");
        products.stream()
                .filter(p -> p.toLowerCase().contains("a"))
                .sorted()
                .forEach(p -> System.out.println("  " + p));

        // Convert to mutable list when you need to modify
        System.out.println("\nAdding to mutable copy:");
        var mutable = new java.util.ArrayList<>(products);
        mutable.add("Printer");
        System.out.println("Mutable list size: " + mutable.size());

        // Immutability check
        System.out.println("\nImmutability check:");
        try {
            products.add("Monitor");
        } catch (UnsupportedOperationException e) {
            System.out.println("add() throws: " + e.getClass().getSimpleName());
        }
        try {
            products.set(0, "Desktop");
        } catch (UnsupportedOperationException e) {
            System.out.println("set() throws: " + e.getClass().getSimpleName());
        }
        try {
            products.remove(0);
        } catch (UnsupportedOperationException e) {
            System.out.println("remove() throws: " + e.getClass().getSimpleName());
        }
    }
}

Expected Output


Products: [Laptop, Smartphone, Tablet, Monitor, Keyboard, Mouse, Headphones, Webcam]
Size: 8
Index 2: Tablet
Contains 'Mouse': true

All products:
  - Laptop
  - Smartphone
  - Tablet
  - Monitor
  - Keyboard
  - Mouse
  - Headphones
  - Webcam

Products with 'a' in name:
  Headphones
  Keyboard
  Laptop
  Smartphone
  Tablet
  Webcam

Adding to mutable copy:
Mutable list size: 9

Immutability check:
add() throws: UnsupportedOperationException
set() throws: UnsupportedOperationException
remove() throws: UnsupportedOperationException

Example 2: List.of() with Java Bean Objects


package com.java9r;

import java.util.List;

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; }

    @Override
    public String toString() {
        return String.format("Product{id='%s', name='%s', price=%.2f}", id, name, price);
    }
}

/**
 * Java 9 – Immutable List.of() with Bean objects.
 */
public class Java9ImmutableListBean {

    public static void main(String[] args) {

        // Create immutable list of Product beans
        var catalog = List.of(
            new Product("P001", "Laptop",      75000.00),
            new Product("P002", "Smartphone",  25000.00),
            new Product("P003", "Tablet",      35000.00),
            new Product("P004", "Monitor",     15000.00),
            new Product("P005", "Keyboard",     2500.00)
        );

        System.out.println("Product Catalog:");
        catalog.forEach(System.out::println);

        // The List is immutable – you cannot add/remove Products
        // But the Product objects themselves ARE mutable (unless you make them immutable)

        System.out.println("\nProducts priced above Rs. 20,000:");
        catalog.stream()
               .filter(p -> p.getPrice() > 20_000)
               .sorted((a, b) -> Double.compare(b.getPrice(), a.getPrice())) // descending
               .forEach(p ->
                   System.out.printf("  %-12s Rs. %,.0f%n", p.getName(), p.getPrice()));

        System.out.println("\nCheapest product: " +
            catalog.stream()
                   .min((a, b) -> Double.compare(a.getPrice(), b.getPrice()))
                   .map(Product::getName)
                   .orElse("none")
        );

        System.out.println("Total catalog value: Rs. " +
            String.format("%,.0f",
                catalog.stream().mapToDouble(Product::getPrice).sum()));
    }
}

Expected Output


Product Catalog:
Product{id='P001', name='Laptop', price=75000.00}
Product{id='P002', name='Smartphone', price=25000.00}
Product{id='P003', name='Tablet', price=35000.00}
Product{id='P004', name='Monitor', price=15000.00}
Product{id='P005', name='Keyboard', price=2500.00}

Products priced above Rs. 20,000:
  Laptop       Rs. 75,000
  Tablet       Rs. 35,000
  Smartphone   Rs. 25,000

Cheapest product: Keyboard
Total catalog value: Rs. 1,52,500

List.of() vs Arrays.asList() vs Collections.unmodifiableList()

Method add/remove? set()? null? Backed by array?
List.of() No (throws) No (throws) No (throws NPE) No
Arrays.asList() No (throws) Yes Yes Yes (reflects changes)
Collections.unmodifiableList() No (throws) No (throws) Depends on backing list Yes (view)

Summary

List.of() in Java 9 is the cleanest way to create an immutable list. It is concise, rejects null elements, and prevents any modification. Use it for constants, configuration values, and any data that should not change after initialization. When you need a modifiable version, pass it to new ArrayList<>(). Unlike Arrays.asList(), List.of() is completely immutable — even the set() method throws an exception.

Topics: CoreJava Java9
← Newer Post Older Post →

Comments

https://www.blogger.com/comment/frame/6690124484600543990?po=7234951362904366827&hl=en&saa=85391&origin=https://www.java9r.com