Java – Using Public Final Rather Than Private Getters

javaobject-oriented-design

I see most immutable POJOs written like this:

public class MyObject {
    private final String foo;
    private final int bar;

    public MyObject(String foo, int bar) {
        this.foo = foo;
        this.bar = bar;
    }

    public String getFoo() {
        return foo;
    }

    public int getBar() {
        return bar;
    }
}

Yet I tend to write them like this:

public class MyObject {
    public final String foo;
    public final int bar;

    public MyObject(String foo, int bar) {
        this.foo = foo;
        this.bar = bar;
    }
}

Note the references are final, so the Object is still immutable. It lets me write less code and allows shorter (by 5 chars: the get and ()) access.

The only disadvantage I can see is if you want to change the implementation of getFoo() down the road to do something crazy, you can't. But realistically, this never happens because the Object is immutable; you can verify during instantiation, create immutable defensive copies during instantiation (see Guava's ImmutableList for example), and get the foo or bar objects ready for the get call.

Are there any disadvantages I'm missing?

EDIT

I suppose another disadvantage I'm missing is serialization libraries using reflection over methods starting with get or is, but that's a pretty terrible practice…

Best Answer

Four disadvantages that I can think of:

  1. If you want to have a read-only and mutable form of the same entity, a common pattern is to have an immutable class Entity that exposes only accessors with protected member variables, then create a MutableEntity which extends it and adds setters. Your version prevents it.
  2. The use of getters and setters adheres to the JavaBeans convention. If you want to use your class as a bean in property-based technologies, like JSTL or EL, you need to expose public getters.
  3. If you ever want to change the implementation to derive the values or look them up in the database, you'd have to refactor client code. An accessor/mutator approach allows you to only change the implementation.
  4. Least astonishment - when I see public instance variables, I immediately look for who may be mutating it and worry that I am opening pandora's box because encapsulation is lost. http://en.wikipedia.org/wiki/Principle_of_least_astonishment

That said, your version is definitely more concise. If this were a specialized class that is only used within a specific package (maybe package scope is a good idea here), then I may consider this for one-offs. But I would not expose major API's like this.