Immutability is a key concept in software development that refers to the inability to modify an object after it has been created. Immutable objects provide various benefits in terms of code safety, thread safety, and code simplicity.
The final keyword in Java is one tool that helps enforce immutability when used correctly. In this module, we'll explore how to use final effectively and design immutable classes in Java.
The final
keyword in Java can be applied to variables, methods, and classes, with different effects:
When applied to a variable, final
means that the variable cannot be reassigned after initialization:
// Final primitive variable
final int MAX_SIZE = 100;
// MAX_SIZE = 200; // This would cause a compilation error
// Final reference variable
final List<String> namesList = new ArrayList<>();
// namesList = new ArrayList<>(); // This would cause a compilation error
namesList.add("John"); // This is allowed - the object's state can be changed
Important distinction: for reference variables, final
prevents reassignment of the reference, but it doesn't make the referenced object immutable.
When applied to a method, final
prevents the method from being overridden in subclasses:
public class Parent {
final void cannotBeOverridden() {
// Method implementation
}
}
public class Child extends Parent {
// This would cause a compilation error
// void cannotBeOverridden() { }
}
When applied to a class, final
prevents the class from being extended:
final class CannotBeExtended {
// Class implementation
}
// This would cause a compilation error
// class Subclass extends CannotBeExtended { }
An immutable class is one whose state cannot be changed after instantiation. Here are the key steps to create an immutable class:
final
to prevent extensionpublic final class ImmutablePerson {
private final String name;
private final int age;
private final List<String> hobbies;
public ImmutablePerson(String name, int age, List<String> hobbies) {
this.name = name;
this.age = age;
// Defensive copy to prevent the reference from being modified externally
this.hobbies = new ArrayList<>(hobbies);
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public List<String> getHobbies() {
// Return a defensive copy to prevent modification
return new ArrayList<>(hobbies);
}
}
Immutable objects offer several advantages:
Many standard Java classes are immutable, including String, Integer, and other wrapper classes.
Learn how to use the final keyword in different contexts.
Understand how to create fully immutable classes.
Why immutability matters in modern software development.
How immutability connects to functional programming techniques.
Starter code for implementing immutable photo filters.
Solution code for the photo filters project.
Additional code-along exercises for this sprint.
Access the sprint challenge for this unit.