Java - Encapsulation
Encapsulation
Access Modifiers
- public: visible everywhere
- protected: visible in same package and subclasses
- (package-private): no modifier; visible in same package
- private: visible only within the declaring class
Getters/Setters with Validation
public class BankAccount {
private int balance; // cents
public synchronized void deposit(int cents) {
if (cents <= 0) throw new IllegalArgumentException("positive only");
balance += cents;
}
public synchronized int getBalance() { return balance; }
}
Immutability
Make state unchangeable after construction to simplify reasoning and enable thread-safety.
public final class Address {
private final String city;
private final java.util.List lines;
public Address(String city, java.util.List lines) {
this.city = city;
this.lines = java.util.List.copyOf(lines); // defensive copy
}
public String getCity() { return city; }
public java.util.List getLines() { return lines; } // unmodifiable
}
Defensive Copies
Never expose internal mutable state directly.
class User {
private final java.util.Date registeredAt;
User(java.util.Date d) { this.registeredAt = new java.util.Date(d.getTime()); }
public java.util.Date getRegisteredAt() { return new java.util.Date(registeredAt.getTime()); }
}
Avoid public mutable fields. Expose behavior, not representation. Keep invariants enforced at the boundaries.
Try it
- Expose an internal
List
safely by returningList.copyOf
instead of the mutable list. - Add validation to a setter and test that invalid values throw exceptions.