Why every Java field should have been final by default.

Introduction

Note to clarify the post: by default I mean having to write something like ‘var’ to have the current behavior (fields can be reassigned), so that if you write nothing the field is automatically final. You still have the choice about being able to reassign or not by using some kind of keyword like ‘var’. I hope it is clearer now !

We all like freedom, but what is freedom when we talk about code ?

You have a lot of freedom with mutable fields, too much, why not let the compiler help you by telling it that your data is immutable ? Is it because you want more possibilities to write code that does not do what you want ?

You sure do not want to, and please do not tell me the final keywords make your code hard to read, it does the exact opposite: it tells the compiler and the reader that your data will never change and this is important information. Most of the time it forces you to write cleaner code that uses less ‘smart tricks’.

(Note: this post is NOT about the ‘other’ final keyword, the one used on classes and methods. It is also not about immutability in general, a much broader topic, but the given links will provide some lecture.)

Examples that illustrate why every Java field should have been final by default:

Example 1: Bad initialization in constructors.

public class UnidentifiedPerson {

 private String _firstName, _lastName;

 public UnidentifiedPerson(String firstName, String lastName) {
   _firstName = firstName;
   // Notice how the lastName is never set and the compiler does not complain !!!
 }
}

There is rarely a need for such code, most of the time you will find that making the fields final will force you to write better constructors.
This is especially true when you have many fields to initialize and when you refactor code.

Example 2: Changing data that is immutable by nature.

public class Person {

 private String _firstName, _lastName;

 public Person(String firstName, String lastName) {
   _firstName = firstName;
   _lastName = lastName;
 }

 public Person changeIdentity(String firstName, String lastName) {
   // It is so easy to change my name.
   _firstName = firstName;
   _lastName = lastName;
   return this;
 }

 @Override
 public String toString() {
   return _firstName + " " + _lastName;
 }

 public static void main(String[] args) {
   System.out.println(new Person("Christophe", "Roussy").changeIdentity("Bill", "Gates"));
 }
}

If you make the fields final the compiler will tell you something interesting:

public PersonFinal changeIdentity(String firstName, String lastName) {
 // The final field PersonFinal._firstName cannot be assigned.
 _firstName = firstName;
 // The final field PersonFinal._lastName cannot be assigned.
 _lastName = lastName;
 return this;
 }

Example 3: Hiding potentially useless code.

public class UselessAssignment {
 public static void main(String[] args) {
 int a, b;
 a = 1;
 b = a;
 a = b;
 // This kind of code is only possible with mutable fields, it will
 // eventually turn up because it can.

 final int fa, fb;
 fa = 1;
 fb = fa;
 fa = fb;
 // The final local variable fa may already have been assigned.
 }
}

When prefixing fields with the final keyword, some undesired code will emerge, it may even explain and solve some bugs.

When not to use final ?

There a only few cases where you want to use mutable fields, such as computing sums:

private static int computeSum(final List<Integer> values) {
   // Here it makes sense not to use final as you do WANT to change the value
   // of sum. Also note how I now use int for sum to avoid autoboxing.
   int sum = 0;
   for (final int value : values) {
     sum += value;
   }
   return sum;
 }

A good way to figure out if you want to remove the final keyword is to ask yourself: “Do I really want this variable to be mutable ?”.

It can sometimes be tricky not to use mutable fields when you are used to them, but on the long term you will discover that it is well worth the effort to help the compiler so it can help you and others. Also note that making a list final does not make the list fully immutable, you will not be able to reassign the list itself, but you will be able to add, remove and modify the contained elements. I have also read that the value of final fields can be changed using reflection (http://www.javaspecialists.eu/archive/Issue096.html), but this is not a concern unless you want to experiment.

Conclusion

It is illogical that the Java language did not do the opposite: every field immutable by default and mutable only when prefixed with some language keyword. Perhaps it comes from the C/C++ mutable flavour Java inherited.

Links:

  1. http://renaud.waldura.com/doc/java/final-keyword.shtml, The Final Word On the final Keyword
  2. http://jeremymanson.blogspot.com/2008/04/immutability-in-java.html, Immutability in Java.
  3. http://www.ibm.com/developerworks/java/library/j-jtp1029.html, Is that your final answer?
  4. http://www.ibm.com/developerworks/java/library/j-jtp02183.html, To mutate or not to mutate?

21 thoughts on “Why every Java field should have been final by default.

  1. I couldn’t agree with you more. My preference would have been to have a “var” keyword or the like to indicate a field is mutable and assume immutability by default.

      • I beg to differ. “var” and “val” look so similar, that trying to spot the difference, becomes a pain (don’t get me started about coloring in the IDE, there are enough visually impaired people out there). The scala guys could have used “var” and “const” or “var” and “final” for example, or simply make “val” the default, simply to make very different things look very different. But it seems language designers usually fail when it comes to looking at their language from a usability/human interface perspective.

      • Good point, I see you already struggled a bit with this, naming can make a big difference indeed. Conceptually it is fine but naming can be a real issue on a daily basis…hope some language designer will read this and take note.

  2. I think there is a disconnect between how often you folks think objects or variables should be final and how often Sun believed it would be on average. Personally I favor Sun’s approach.

    Depending on business rules, I would likely not make a Person object final. People can change names, genders, hair color, etc without becoming new people. If you force the system to create a new Person object every time some data changes, you are offloading the change responsibility to the factory that creates it, which IMO is more error prone than just making the fields mutable.

    Usually I save immutability for things that cannot change over time, such as logging dates and entries, financial transactions, historical facts, commands from the command pattern, etc.

    • The Person object would not at all be “final”. The final keyword only prevents the reassignment of the field, but you’re still able to change the state of the Person object, if it allows that.

      • The person was just an example, perhaps not the best one because you can change your name to some degree, perhaps I should have chosen the birthdate…

        It mostly depends on your business logic, the point is that asking yourself if the data can change is important.
        Using non-final fields when you do not intend to change them anyways is error prone.

  3. Personally I agree with this as well. Actually I’d rather they “force” best practice into the language if possible.

    I know that goes against most dynamic languages like Ruby/Python/Perl especially Perl where TIMTOWDI rules (which is a double edged sword for me).

    Some other things I’d like the compiler to enforce if possible are indentation like they do in Python.

    Create a designation for utility classes that will imply static and final with no constructor by default.

  4. This example works for the simplest use case, but I fail to see how to proceed with a persistent class with 70 attributes, half of them optional. Constructor injection has its limits.

    As a side note, your computeSum example should use int instead of Integer.

    • Hey thanks for commenting,
      to fight against big constructors you can use the Builder pattern.
      I used Integer in my example because my List contains Integers and this example was only written to show an example where mutable data is useful. You meant using int for the sum ?
      Like: int sum = 0; for (int value : …)

      • Anyways, the Builder itself must not be immutable, and that affects somehow the point of the article (that all attributes must be final by default). I see value in this, but I am not sure how much clutter (Builder pattern, constructor injection) it would be adding to the code.

        About ‘sum’, if it’s Integer you are autoboxing the sum value on every iteration (since Integer is immutable while int is not).

      • It seems the title is not as clear as I thought. By default I mean that instead of having to write final, fields would automatically be final, and to make them non-final you would have to write something like var. So you still have as much choice as before, just the default setting is final instead of non-final.

  5. Your suggestion is fine, but there’re many situations where it’s hard to achieve; if Hibernate is used for persistence, a no-arg constructor is required. If Spring is employed as IOCC, many times setter injection is easier to configure and works better than constructor injection.

    Being able to use final everywhere would be nice, yet it’s unpractical. An intermediate builder object is often easier to implement whenever it’s needed.

    • It is hard to achieve indeed, but you have to know that I am not against using non final fields when it simplifies the design and makes code easier to maintain. But IMHO most local variables and all parameters should be final.

  6. Making Java fields final by default would break backwards compatibility by default. In addition, fields are not final by default in many other programming languages, including C, C++, C#, Visual Basic, and PHP.

    An important difference between final fields and normal fields in Java SE 5 and later is that Java SE 5 and later guarantees that writes to final fields within a constructor are not reordered with write operations that happen after the execution of the constructor.

    • Yes, Java did inherit the ‘non-final’ fields from such languages and many programmers are used to this behaviour (least surprise).
      I did not mean this to be something to add to the next Java version, I just wish it had always been this way for some of the reasons I mentioned in the post.

      I think you raised an important point by talking about reordering, it was not part of my post, I found this quote regarding this matter:

      “If a field that was not final is changed to be final, then it can break compatibility with pre-existing binaries that attempt to assign new values to the field.”

      13.4.9 final Fields and Constants, here: Binary Compatibility

  7. I hit this for the exact same reason – kind of stupid to clutter code with ‘best practice’ when it should have been that way by default.

Leave a reply to Jose Fernandez Cancel reply