← Back to Home

Module 3: Immutability and Final

Learning Objectives

Introduction to Immutability

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.

Understanding the Final Keyword

The final keyword in Java can be applied to variables, methods, and classes, with different effects:

Final Variables

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.

Final Methods

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() { } 
}

Final Classes

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

Creating Immutable Classes

An immutable class is one whose state cannot be changed after instantiation. Here are the key steps to create an immutable class:

  1. Declare the class as final to prevent extension
  2. Make all fields private and final
  3. Don't provide setter methods
  4. If the class contains mutable objects:
    • Make defensive copies in the constructor
    • Make defensive copies in the getter methods
  5. Ensure that methods don't modify the object's state
public 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);
    }
}

Benefits of Immutability

Immutable objects offer several advantages:

Many standard Java classes are immutable, including String, Integer, and other wrapper classes.

Key Topics

Final Keyword

Learn how to use the final keyword in different contexts.

  • Final variables
  • Final methods
  • Final classes

Immutable Classes

Understand how to create fully immutable classes.

  • Design principles
  • Defensive copying
  • Handling collections

Benefits of Immutability

Why immutability matters in modern software development.

  • Thread safety
  • Caching
  • Security

Functional Programming

How immutability connects to functional programming techniques.

  • Pure functions
  • Side-effect-free code
  • Java Stream API

Resources

Photo Filters Project Starter

Starter code for implementing immutable photo filters.

Photo Filters Project Solution

Solution code for the photo filters project.

Code-Alongs

Additional code-along exercises for this sprint.

Sprint Challenge

Access the sprint challenge for this unit.