Blog

Why Effective Java Says Use Accessors, Not Public Fields

A developer podcast episode covering Item 14 of Effective Java makes a point that sounds obvious but trips up codebases regularly: in public classes, use accessor methods instead of public fields. The episode frames it as a flexibility rule—what you expose as public is locked in, and locking in a raw field is a long-term burden.

The core argument is about API commitment. Once a field is public, its type, name, and semantics are part of your contract. Change them, and every caller breaks. Once an accessor exists, the underlying representation can evolve without touching the public surface.

What the rule actually says

Item 14 is precise: accessor methods belong in public classes. Joshua Bloch does not extend this to private or package-private classes, and that distinction matters. Engineers who blanket-apply getters and setters to every class end up with classes that balloon from 15 lines to 30–50 lines of accessor code for a type that no code outside the package will ever see.

The cost of accessor methods is not zero. The benefit is not always positive.

Why public fields are quietly dangerous

The danger is not the field itself. The danger is the commitment it creates. Once a public field is part of your API, its type, name, and meaning are locked. Changing any of them later is a breaking change, full stop.

Accessor methods invert this. They keep the public surface stable while letting internal representation evolve. Need to switch from a long to a String? Possible with an accessor. Impossible without a major version bump with a public field.

Even Java itself learned this lesson the hard way. The Dimension class exposes internal fields that created performance problems still present in the JDK today. Bloch points out that Java's own library violates this advice in places like the Point and Dimension classes, and those decisions have proven costly.

When direct fields are acceptable

The podcast episode correctly flags the other side of this coin. For private or package-private classes, exposing fields directly is often fine—and sometimes preferable. The customer code that uses your library or package is already coupled to your implementation anyway. If you need to change the internal representation, you can do so without worrying about the public API because there is no public API.

The exception is immutable fields. Public final fields carry far less risk than mutable public fields because the representation cannot change. You lose some flexibility, but you are not creating a mutable aliasing problem.

Accessor vs. Direct Field: Decision Checklist

Condition Recommendation
Class is public (exposed beyond its package) Use accessor methods
Class is private or package-private Direct fields are acceptable
Field is mutable Accessor methods strongly recommended
Field is final and immutable Direct fields lower risk, accessors still cleaner
Need to enforce invariants on access Accessor methods required
Need to add side effects later Accessor methods required
Class is a simple data container, never exposed Direct fields reduce boilerplate

What to watch for

Watch for code review patterns that flag public fields in public classes before they ship. Most IDE inspections catch this, but they also flag public fields in private classes, where the rule does not apply. The skill is knowing the scope.

Bottom line: use accessors in public classes, keep private classes lean, and remember that immutability softens but does not eliminate the risk of direct field exposure.

Key takeaways

  • Effective Java Item 14 recommends accessor methods for public classes, not for private or package-private ones.
  • Public fields lock in internal representation and make future changes breaking.
  • Accessor methods preserve API flexibility while allowing internal evolution.
  • Immutable fields reduce the risk of public field exposure but do not eliminate it.

Frequently asked questions

What does Effective Java Item 14 recommend?

It recommends using accessor methods instead of public fields, scoped specifically to public classes.

Does the rule apply to private classes?

No. Private or package-private classes can expose fields directly with less risk because they have no public API surface.

Why are public fields considered risky?

They lock the internal representation into the public API, making any future change a breaking change for all callers.

Are there any exceptions to this rule?

Yes. Immutable fields (public final) carry less risk because the representation cannot change. Java's own Point class is cited as an example of the opposite—mutable public fields that caused lasting problems.

How can Android developers apply this in practice?

Use accessors for any class exposed beyond its package. For internal classes, favor direct field access to reduce boilerplate.

Related