CoreJava Java9

Java 9 – Factory Methods for Immutable Set: Set.of() with Strings and Beans

Java 9 – Factory Methods for Immutable Set: Set.of() with Strings and Beans

Java 9 introduced Set.of(), a convenient factory method for creating immutable sets in one line. Before Java 9, you had to create a HashSet, add elements individually, and then wrap it with Collections.unmodifiableSet(). The new factory method is concise, null-safe, and produces a truly unmodifiable set.

This tutorial covers two practical examples: using Set.of() with plain strings and with custom Java Bean objects.

What is Set.of()?

Set.of(E... elements) is a varargs static factory method on the Set interface. It was defined in JEP 269 and is available from Java 9 onwards. The resulting set has these properties:

  • Truly immutable — add, remove, and clear throw UnsupportedOperationException
  • No null elements — throws NullPointerException if null is passed
  • No duplicate elements — throws IllegalArgumentException for duplicates
  • No guaranteed iteration order (unlike LinkedHashSet)

Example 1: Set.of() with Strings


package com.java9r;

import java.util.Set;

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

    public static void main(String[] args) {

        // Create an immutable set of programming languages
        var languages = Set.of(
            "Java", "Python", "JavaScript", "Go", "Kotlin", "Rust", "C#"
        );

        System.out.println("Languages: " + languages);
        System.out.println("Size: " + languages.size());
        System.out.println("Contains 'Java': " + languages.contains("Java"));
        System.out.println("Contains 'PHP': "  + languages.contains("PHP"));

        // Iterate using for-each
        System.out.println("\nAll languages:");
        languages.stream().sorted().forEach(l -> System.out.println("  - " + l));

        // Filter using Stream API
        System.out.println("\nLanguages with 'a' in name:");
        languages.stream()
                 .filter(l -> l.toLowerCase().contains("a"))
                 .sorted()
                 .forEach(l -> System.out.println("  " + l));

        // Convert to mutable when you need to add/remove
        var mutableSet = new java.util.HashSet<>(languages);
        mutableSet.add("TypeScript");
        System.out.println("\nMutable set size: " + mutableSet.size());

        // Immutability tests
        System.out.println("\nImmutability checks:");
        try { languages.add("Scala"); }
        catch (UnsupportedOperationException e) {
            System.out.println("add() blocked: " + e.getClass().getSimpleName());
        }
        try { languages.remove("Java"); }
        catch (UnsupportedOperationException e) {
            System.out.println("remove() blocked: " + e.getClass().getSimpleName());
        }

        // Duplicate key check
        System.out.println("\nDuplicate key check:");
        try { Set.of("A", "B", "A"); }   // same element twice
        catch (IllegalArgumentException e) {
            System.out.println("Duplicate throws: " + e.getClass().getSimpleName());
        }

        // Null check
        try { Set.of("A", null); }
        catch (NullPointerException e) {
            System.out.println("Null throws: " + e.getClass().getSimpleName());
        }
    }
}

Expected Output


Languages: [Go, Kotlin, Rust, Java, JavaScript, Python, C#]
Size: 7
Contains 'Java': true
Contains 'PHP': false

All languages:
  - C#
  - Go
  - Java
  - JavaScript
  - Kotlin
  - Python
  - Rust

Languages with 'a' in name:
  Java
  JavaScript

Mutable set size: 8

Immutability checks:
add() blocked: UnsupportedOperationException
remove() blocked: UnsupportedOperationException

Duplicate key check:
Duplicate throws: IllegalArgumentException

Null throws: NullPointerException

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


package com.java9r;

import java.util.Objects;
import java.util.Set;

class Product {
    private final String id;
    private final String name;
    private final 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; }

    // equals() and hashCode() are required for Set to detect duplicates
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Product)) return false;
        return Objects.equals(id, ((Product) o).id);
    }

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

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

/**
 * Java 9 – Immutable Set.of() with Bean objects.
 * IMPORTANT: The bean must implement equals() and hashCode()
 * for duplicate detection to work correctly.
 */
public class Java9ImmutableSetBean {

    public static void main(String[] args) {

        var catalog = Set.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.stream()
               .sorted((a, b) -> a.getId().compareTo(b.getId()))
               .forEach(System.out::println);

        System.out.println("\nTotal products: " + catalog.size());

        // Check if a specific product is in the set
        var search = new Product("P003", "Tablet", 0); // price ignored in equals()
        System.out.println("\nSearching for P003: " + catalog.contains(search));

        // Find most expensive
        catalog.stream()
               .max((a, b) -> Double.compare(a.getPrice(), b.getPrice()))
               .ifPresent(p -> System.out.println("Most expensive: " + p.getName()
                                                  + " (Rs. " + p.getPrice() + ")"));

        // Find products under Rs. 30,000
        System.out.println("\nAffordable products (under Rs. 30,000):");
        catalog.stream()
               .filter(p -> p.getPrice() < 30_000)
               .sorted((a, b) -> Double.compare(a.getPrice(), b.getPrice()))
               .forEach(p ->
                   System.out.printf("  %-12s Rs. %,.0f%n", p.getName(), p.getPrice()));
    }
}

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}

Total products: 5

Searching for P003: true
Most expensive: Laptop (Rs. 75000.0)

Affordable products (under Rs. 30,000):
  Keyboard     Rs. 2,500
  Monitor      Rs. 15,000
  Smartphone   Rs. 25,000

Set.of() vs Other Set Creation Methods

Method Immutable? Null allowed? Duplicates? Order
Set.of() Yes No (NPE) No (IAE) Unspecified
new HashSet<>() No Yes (one null) Silently ignored Unspecified
new LinkedHashSet<>() No Yes (one null) Silently ignored Insertion order
Collections.unmodifiableSet() Yes (view) Depends on backing Silently ignored Depends on backing

Summary

Set.of() in Java 9 is the cleanest way to create an immutable set of unique elements. It is concise, rejects nulls and duplicates at construction time, and produces a completely unmodifiable set. When using Set.of() with custom Bean objects, always ensure equals() and hashCode() are implemented — otherwise duplicate detection will not work correctly. For a modifiable copy, wrap it in new HashSet<>().

Topics: CoreJava Java9
← Newer Post Older Post →

Comments

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