Immutability Summary
Aliasing
- Multiple references pointing to the same object
- Changes through one reference affect all references
- Can lead to unexpected behavior
-
Example:
List<Integer> list1 = new ArrayList<>(); List<Integer> list2 = list1; // alias created list1.add(1); // affects both list1 and list2
-
Common Issues:
- Unintended modifications
- Debugging complexity
- Concurrency challenges
Immutability Concept
- Objects cannot be modified after creation
- All fields are final
- No mutator methods
- Returns new objects for modifications
- Example:
final class Point { private final double x; private final double y; public Point(double x, double y) { this.x = x; this.y = y; } public Point moveTo(double newX, double newY) { return new Point(newX, newY); // returns new instance } }
Benefits of Immutability
-
Thread Safety:
- Safe for concurrent access
- No synchronization needed
-
Easier Reasoning:
- No state changes to track
- Predictable behavior
-
Security:
- Cannot be modified maliciously
- Safe to share references
-
Caching:
- Can cache safely
- No invalidation needed
Creating Immutable Classes
- Make class final
- Make fields private and final
- No setter methods
- Return new instances for modifications
- Protect mutable fields
- Example:
final class Circle { private final Point center; private final double radius; public Circle(Point center, double radius) { this.center = new Point(center.getX(), center.getY()); // defensive copy this.radius = radius; } public Point getCenter() { return new Point(center.getX(), center.getY()); // return copy } }
Copy-on-Write Pattern
- Create new object for modifications
- Share unmodified objects
- Example:
public Circle resize(double factor) { return new Circle(this.center, this.radius * factor); }
Best Practices
- Make classes immutable by default
- Use final liberally
- Create defensive copies
- Document immutability
- Consider performance implications
- Use factory methods for flexibility