CoreJava Java9

Java 9 – Immutable Set of Objects Using Set.of()

Java 9 – Immutable Set of Objects Using Set.of()

Java 9's Set.of() creates an unmodifiable set in a single expression. This post demonstrates using it with a custom bean (POJO), explains the uniqueness constraint, and shows how Set.of() differs from List.of() for object collections.

Key Difference: Set vs List

A Set does not allow duplicate elements and does not guarantee iteration order. When you use Set.of() with custom objects, equality is determined by the equals() method. If your bean does not override equals(), two different new Product(...) calls with identical field values are treated as different objects (reference equality).

Product.java

package com.java9r;

import java.util.Objects;

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

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Product)) return false;
        Product p = (Product) o;
        return Objects.equals(id, p.id);   // products are equal if same ID
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }

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

ImmutableSetWithBean.java

package com.java9r;

import java.util.Set;

public class ImmutableSetWithBean {

    public static void main(String[] args) {

        // Create immutable set of Product beans
        Set<Product> products = Set.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 Set (order not guaranteed):");
        System.out.println("=====================================");
        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());

        // Check membership
        Product search = new Product("101", "Smartphone", 25000.0);
        System.out.println("\nContains P101? " + products.contains(search));

        // Modification throws UnsupportedOperationException
        try {
            products.add(new Product("105", "Mouse", 1500.0));
        } catch (UnsupportedOperationException e) {
            System.out.println("Cannot add to immutable set: " + e.getClass().getSimpleName());
        }

        // Duplicate ID at creation time throws IllegalArgumentException
        try {
            Set<Product> bad = Set.of(
                new Product("200", "A", 100.0),
                new Product("200", "A", 100.0)   // same id = same equals/hashCode
            );
        } catch (IllegalArgumentException e) {
            System.out.println("Duplicate element rejected: " + e.getClass().getSimpleName());
        }
    }
}

Output

Products Set (order not guaranteed):
=====================================
Id:    103
Name:  Monitor
Price: 15000.0
-------------------------
Id:    102
Name:  Tablet
Price: 35000.0
-------------------------
Id:    101
Name:  Smartphone
Price: 25000.0
-------------------------
Id:    104
Name:  Keyboard
Price: 2500.0
-------------------------
Id:    100
Name:  Laptop
Price: 75000.0
-------------------------
Total products: 5

Contains P101? true
Cannot add to immutable set: UnsupportedOperationException
Duplicate element rejected: IllegalArgumentException

Iterating Over the Set

// 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 — sorted to get consistent output
products.stream()
        .sorted((a, b) -> a.getId().compareTo(b.getId()))
        .forEach(System.out::println);

// 4. Stream filter
products.stream()
        .filter(p -> p.getPrice() > 20000)
        .forEach(p -> System.out.println(p.getName() + " — ₹" + p.getPrice()));

Set.of() vs List.of() With Beans

Feature List.of() Set.of()
Duplicate elements Allowed Not allowed — throws IllegalArgumentException
Iteration order Insertion order preserved Not guaranteed
Index access list.get(0) works No index access
Contains check O(n) O(1) — uses hash
Requires equals/hashCode Only for contains() Always — for duplicate detection

Important: Override equals() and hashCode()

Without overriding equals() and hashCode(), two new Product("100", ...) objects are treated as different even if all fields are identical (reference equality). This means Set.of() would accept them as non-duplicates, and contains() would return false for a freshly created object with the same ID. Always override both methods in beans used inside sets or maps.

Summary

Use Set.of() with custom beans when you need an unmodifiable collection that guarantees no duplicate elements and provides fast O(1) membership checks. Ensure the bean overrides equals() and hashCode() so equality is based on meaningful business identity (e.g., product ID) rather than object reference. Like List.of(), the resulting set is structurally immutable — but individual bean fields can still be modified unless the bean itself is immutable.

Topics: CoreJava Java9
← Newer Post Older Post →

Comments

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