Immutable classes in Java are those which once created, their state cannot be changed. This is particularly useful when you need to ensure that an object remains constant throughout its lifecycle and achieve thread safety without synchronization. Immutable objects are foundational for functional programming style, allowing for easier maintenance and understanding of the application flow.
In this article, you will learn how to create an immutable class in Java. Explore key techniques to ensure the class cannot be modified after its instantiation, from using final fields to returning copies of mutable objects. By applying these strategies, you enhance the robustness and thread-safety of your applications.
Define a final class with a final data field.
Provide a constructor to set the field.
public final class ImmutableValue {
private final int value;
public ImmutableValue(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
This code outlines a simple immutable class ImmutableValue
with one field value
. Since it's declared with the final
keyword, you cannot change the value
once it's set, nor can you inherit from this class.
Consider a class that includes a mutable List
as a field.
Make a deep copy of the list in the constructor and on the getter method.
import java.util.ArrayList;
import java.util.List;
import java.util.Collections;
public final class ComplexImmutable {
private final List<String> items;
public ComplexImmutable(List<String> items) {
this.items = new ArrayList<>(items);
}
public List<String> getItems() {
return Collections.unmodifiableList(items);
}
}
This example demonstrates an immutable class ComplexImmutable
that contains a mutable object (a List
). The class makes a deep copy of the list in its constructor and provides it in a way that the internal list can't be modified from outside, thus maintaining immutability.
Create instances of your immutable class.
Attempt to modify the instances and verify if the state changes.
public class TestImmutable {
public static void main(String[] args) {
ImmutableValue val = new ImmutableValue(100);
System.out.println("Value: " + val.getValue());
List<String> list = new ArrayList<>();
list.add("Hello");
list.add("World");
ComplexImmutable complex = new ComplexImmutable(list);
System.out.println("Items: " + complex.getItems());
list.add("Test");
System.out.println("After trying to modify original list: " + complex.getItems());
}
}
In this test code, you create an object of ImmutableValue
and try modifying ComplexImmutable
by changing the original list. Notice how the output reveals that ComplexImmutable
's content remains unchanged, signifying true immutability.
Crafting immutable classes in Java provides great benefits in ensuring data consistency and simplifying concurrency control in applications. By adhering to principles such as final class declarations, final fields, and careful handling of mutable objects, you equip your programs with definitively unchangeable objects. Expanding this pattern will streamline your system's architecture, paving the way for more maintainable and error-resistant code. Implement these strategies in your next project to harness the power of immutability.