Immutable Type: public final fields vs. getter

I need a small Container-Class for storing some Strings which should be immutable. As String itself is an immutable type, I thought of something like that:

public final class Immu
{
  public final String foo;
  public final String bar;

  public Immu(final String foo, final String bar)
  {
    this.foo = foo;
    this.bar = bar;
  }
}

Many people seem to object using public fields at all and use Getters instead. IMHO this would be just boilerplate in this case, because String itself is immutable.

Other thoughts I may be missing on this one?


Solution 1:

I would do what you believe is simplest and clearest. If you have a data value class which is only used by a restricted number of classes. esp a package local class. then I would avoid getter/setters and use package local or public fields.

If you have a class which you expect other modules/developers to use, following a getter/setter model may be a safer approach in the long run.

Solution 2:

The problem is the uniform access principle. You may later need to modify foo so that it's obtained through a method instead of being fixed, and if you exposed the field instead of a getter, you'll need to break your API.

Solution 3:

This answer is obviated:

Why not

interface Immu { String getA() ; String getB ( ) }

Immu immu ( final String a , final String b )
{
       /* validation of a and b */
       return new Immu ( )
       {
              public String getA ( ) { return a ; }

              public String getB ( ) { return b ; }
       }
}

Solution 4:

I found this thread hoping for some actual arguments, but the answers I've seen here didn't help me all that much. After some more research and thinking I think the following has to be considered:

  • public final looks cleanest for immutable types.
  • Mutable types could be altered by accessors even if this is not intended - in concurrent environments this could lead to a lot of headaches.
  • There can be no no-arguments constructor. This is importent if you need factory methods (e.g. for LMAX Disruptor). In a similar way instantiating your objects via reflection becomes more complicated.
  • Getters and setters can have side effects. Using public final clearly tells the programmer that no hidden magic is occuring and the object is inherently dumb :)
  • You can't return a wrapper or a derived class instance to the accessor. Then again, this is something you should know about when the field is assigned its value. In my opinion container classes should not be concerned about what to return to whom.

If you're mid development and no guideline is stopping you and the project is isolated or you have control over all involved projects I'd suggest using public final for immutable types. If you decide you need getters later on, Eclipse offers Refactor -> Encapsulate Field... which automatically creates these and adjusts all references to the field.

Solution 5:

I use the public-final-field (anti?)pattern on home projects for classes which are basically an immutable data structure with a constructor, along with absolute basics like equals(), hashCode(), toString(), etc. if required. (I'm avoiding the word "struct" because of the various different language interpretations of it.)

I wouldn't bring this approach to someone else's codebase (work, public project, etc) because it would likely be inconsistent with other code, and principles like When In Rome or Least Surprise take priority.

That said, with regard to Daniel C. Sobral's and aioobe's answers, my attitude is that if the class design becomes a problem because of unforeseen developments, it's the work of 30 seconds in an IDE to privatise the fields and add accessors, and no more than 5 or 10 minutes to fix broken references unless there are hundreds of them. Anything that fails as a result gets the unit test it should have had in the first place.:-)

[Edit: Effective Java is quite firmly against the idea, while noting that it's "less harmful" on immutable fields.]