How to Use Guava Immutable Collections: A Complete Guide to ImmutableList, ImmutableSet, and ImmutableMap
Use Guava immutable collections by creating immutable instances via static factory methods like ImmutableList.of() or ImmutableList.copyOf(), or use the Builder pattern for complex construction, ensuring thread-safe, null-safe, and unmodifiable data structures.
The google/guava library provides a robust framework for immutable collections that extend the standard Java Collections API with performance and safety guarantees. This guide covers the practical implementation of Guava immutable collections based on the actual source code in the com.google.common.collect package.
Why Use Guava Immutable Collections?
Guava immutable collections offer three primary advantages over standard mutable collections:
- Thread-safety – No synchronization is required because the data cannot be mutated after creation.
- Performance – Operations avoid defensive copying overhead; underlying data structures are stored efficiently.
- Predictable behavior – Any attempt to modify the collection throws
UnsupportedOperationException.
These characteristics make them ideal for constant data, configuration objects, and concurrent environments.
Core Architecture and Base Classes
All immutable collections in Guava extend the abstract class ImmutableCollection located at guava/src/com/google/common/collect/ImmutableCollection.java. This base class defines common immutable behavior and enforces the contract that elements cannot be added or removed after construction.
Concrete implementations include:
ImmutableList– Ordered sequence with indexed accessImmutableSet– Unordered collection of unique elementsImmutableMap– Key-value mappings with unique keys
Each concrete class resides in its respective source file (ImmutableList.java, ImmutableSet.java, ImmutableMap.java) and provides collection-specific factory methods.
Creating Guava Immutable Collections
Using Static Factory Methods (of() and copyOf())
The simplest way to create immutable collections is through static factory methods that perform null-checks on every element.
ImmutableList.of() creates instances from explicit elements (optimized for up to 12 arguments) or var-args:
ImmutableList<String> colors = ImmutableList.of("red", "green", "blue");
ImmutableList.copyOf(Iterable<? extends E>) creates an immutable copy from any existing Iterable while preserving order:
List<Integer> mutable = new ArrayList<>(Arrays.asList(1, 2, 3));
ImmutableList<Integer> immutable = ImmutableList.copyOf(mutable);
Similar factories exist for sets and maps:
ImmutableSet<Integer> primes = ImmutableSet.of(2, 3, 5, 7, 11);
ImmutableMap<String, Integer> ages = ImmutableMap.of("Alice", 30, "Bob", 25);
Using the Builder Pattern
For complex construction logic or conditional additions, use the builder() method which returns a mutable Builder instance. This pattern is defined in ImmutableList.java (line 69) and analogous classes:
ImmutableList.Builder<String> builder = ImmutableList.builder();
for (String s : someSource) {
if (s.startsWith("A")) {
builder.add(s);
}
}
ImmutableList<String> aNames = builder.build();
The builder can be reused to create multiple immutable instances, making it efficient for batch processing.
Collecting from Java Streams
For Java 8+ stream processing, use toImmutableList() (defined in guava/src/com/google/common/collect/CollectCollectors.java) to collect results directly:
ImmutableList<Integer> squares = IntStream.rangeClosed(1, 5)
.map(i -> i * i)
.boxed()
.collect(ImmutableList.toImmutableList());
Null Safety and Defensive Programming
All Guava immutable collection factories perform strict null-checks on each element. If any element is null, the factory immediately throws NullPointerException during construction rather than allowing nulls to exist in the supposedly immutable structure. This ensures that once created, the collection is truly immutable and free of null-related surprises.
Performance Characteristics
According to the source implementation in ImmutableCollection.java, these collections achieve performance through several optimizations:
- No defensive copying – When using
copyOf(), Guava analyzes the input to avoid unnecessary duplication if the source is already immutable. - Memory efficiency – Empty collections return singleton instances (e.g.,
ImmutableList.of()returns the same empty list reference every time). - Structural sharing – Builders use efficient array resizing strategies before finalizing the immutable structure.
Summary
- Guava immutable collections reside in
com.google.common.collectand extendImmutableCollection. - Create instances via
of()for literals,copyOf()for converting existing collections, orbuilder()for complex logic. - Use
toImmutableList()(and similar collectors) for Stream API integration. - All factories reject null elements with
NullPointerExceptionto maintain immutability contracts. - Attempting modification operations throws
UnsupportedOperationException.
Frequently Asked Questions
What happens if I try to modify a Guava immutable collection?
Any attempt to call mutating methods like add(), remove(), or clear() throws UnsupportedOperationException. This is enforced by the base implementation in ImmutableCollection.java and all concrete subclasses, ensuring runtime protection against accidental modification.
Can I create a Guava immutable collection containing null elements?
No. All factory methods and builders in ImmutableList, ImmutableSet, and ImmutableMap perform explicit null checks during construction. If you attempt to pass a null element, the method throws NullPointerException immediately, preventing nulls from entering the immutable data structure.
Are Guava immutable collections thread-safe?
Yes. Because the contents cannot change after creation, Guava immutable collections are inherently thread-safe without requiring synchronization. Multiple threads can safely read from the same instance simultaneously, as implemented in the thread-safe publication guarantees of the ImmutableCollection hierarchy.
When should I use copyOf() versus the Builder pattern?
Use copyOf() when you have an existing Iterable or collection that you want to convert to an immutable form in a single operation. Use the Builder pattern when you need to construct the collection programmatically with loops, conditionals, or multiple steps before finalizing the immutable instance.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →