💎 What is an Immutable Object?
An immutable object is an object whose state cannot be changed after it’s created.
- All fields are final (or effectively final).
- No setters (modification methods).
- If it contains references to mutable objects, those references are deep-copied or properly handled (defensive copying).
- Safe to share between threads (since the object can’t change, it’s inherently thread-safe).
✅ Benefits of Immutability
Benefit | Why it matters |
---|---|
Thread-safe | No synchronization needed — read-only objects are always safe. |
Simpler code | No complex state changes to track — just construct and use. |
Safe as keys | Perfect for hash keys (like in HashMap ). |
Cache-friendly | Since they can’t change, they can be cached or memoized. |
📜 Examples of Immutable Classes in Java
Class | Notes |
---|---|
String | Classic example — every modification returns a new String . |
Integer , Double , etc. | All wrapper classes for primitives are immutable. |
LocalDate , LocalDateTime | New Date-Time API (Java 8+) is immutable. |
⚙️ Example — Immutable Person Class
public final class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
final
class: No subclass can accidentally make it mutable.final
fields: Can only be set once, in the constructor.- No setters: No way to change after creation.
🛠️ Example — Immutable with Mutable Field (Defensive Copying)
If your class contains a mutable object, like a List
or Date
, you must protect it:
public final class Employee {
private final String name;
private final List<String> skills;
public Employee(String name, List<String> skills) {
this.name = name;
this.skills = new ArrayList<>(skills); // Defensive copy
}
public List<String> getSkills() {
return new ArrayList<>(skills); // Return a copy to prevent outside modification
}
public String getName() {
return name;
}
}
⚠️ Common Mistake — Returning Mutable References Directly
public List<String> getSkills() {
return skills; // Now caller can modify the internal list
}
Always return a copy to preserve immutability.
🔥 Example — Immutable String
String s = "Hello";
s = s.concat(" World"); // This creates a new String object — s was never modified
🔗 Immutable vs Mutable — Quick Summary
Feature | Immutable Object | Mutable Object |
---|---|---|
Can change state | ❌ No | ✅ Yes |
Thread-safe | ✅ Yes | ❌ No (usually) |
Safer as map key | ✅ Yes | ⚠️ Risky if mutable fields change |
Performance | Slightly slower if heavy copying needed | Faster if frequent updates required |
📚 Summary — Immutability Checklist
✅ Class is final (cannot be subclassed).
✅ All fields are private final.
✅ No setters or mutators.
✅ Defensive copying for mutable fields (like lists, maps, dates).
✅ No methods that expose internal mutable state.
💡 When to Use Immutable Objects?
✅ Value objects (like Money
, Coordinate
).
✅ Entities used in multithreaded code.
✅ Objects used as keys in maps.
✅ Configurations and system properties that shouldn’t change after creation.