OOP · 337 words · 2 minute read
Java Encapsulation: Protect State with Small, Useful Methods
By Priyanshu Rauth · Published 2026-09-04 · Updated 2026-09-04
Encapsulation is not a ritual of adding getters and setters to every field. It means a class controls the rules of its own state. A bank account should not let any caller assign a negative balance, and an inventory item should not let stock silently become negative. Good methods express an allowed transition such as deposit, sell, or rename.
Choose an invariant first
An invariant is a condition that remains true after construction and after every public method returns. Examples include “quantity is never negative” or “a fraction denominator is not zero.” Once this sentence exists, constructors can validate essential values and methods can reject invalid changes at the boundary. Private fields make it impossible to bypass those checks accidentally.
class Counter {
private int value;
Counter(int openingValue) { if (openingValue < 0) throw new IllegalArgumentException(); value = openingValue; }
void increment() { value++; }
boolean decrement() { if (value == 0) return false; value--; return true; }
int value() { return value; }
}
public class Main {
public static void main(String[] args) {
Counter counter = new Counter(1);
counter.decrement();
System.out.println(counter.value());
}
}The output is 0. A second decrement returns false and leaves the object valid rather than manufacturing a negative counter.
Expose behavior, not representation
A getter is useful when callers need to observe a value. A setter is useful only when arbitrary replacement preserves the class contract. Returning a mutable collection is another form of exposing representation; prefer an unmodifiable view or a purposeful method such as addSong. Immutable fields and small constructors are often simpler than a field that can change through several unrelated setters.
Common mistakes
- Using static fields for per-object state.
- Validating in one method but leaving another public path around the rule.
- Using exceptions for an expected, ordinary outcome without a documented reason.
- Making a class large enough to own unrelated responsibilities.
Practice next
Work through constructors, bank account operations, and inventory management. Then use the OOP compiler examples to add invalid inputs deliberately. The goal is to see that rejected input keeps the object’s previous valid state intact.
Continue with the Java practice path · Try code in the Java compiler