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

  1. Expose an internal List safely by returning List.copyOf instead of the mutable list.
  2. Add validation to a setter and test that invalid values throw exceptions.