why fields should be final in immutable class?
Asked Answered
G

7

11

Strategy for defining immutable class says that

all the fields should be final.

For ex:

private String name;

Why does it have to be final?

Since I am not giving setter methods for it? It can't be changed. Thanks.

Granulate answered 4/9, 2013 at 7:32 Comment(0)
E
21

If you read

private final String name;

you know the field is immutable.

If you read

private String name;

you have to read the entire class to check it is not changed anywhere. This is means much more work for you.

You may remember now, having just written the class that you didn't add a setter, but after writing many more classes you read your own class six month later, you won't remember reliably.

Even if it is not changed now, someone (possibly yourself) could change it later by adding code. However, you might have made the assumption the value won't change.

In short, only make it non-final when you mean the value to change, and make it final when you didn't expect it to change. Don't leave it as a may be/may be not.


Now imagine you are used to being clear about which fields can be changed and which cannot. This saves you a lot of work when reading some else's code. But you discover that you are reading code which is not clear and non-final doesn't mean it was changed, it now means you have to check things, you wouldn't normally have to check which is one more headache in trying to understand some code you really don't need.


A simple example of how much harder it is to read code to determine if a field is effectively final.

public class A {
    static class B  {
        private int x;
    }

    // some code

This all looks fine up to this point, no setters or even methods in B. So B.x is immutable right?

    static class C {
        public void update(B b, int x) {
            b.x = x; // this really compiles
        }
    }
}

Oops no, you have to read the whole class file.

It is far better for you to make every field you can final (which should have been the default IMHO) when you write the code, rather than leaving it for someone to figure out later.

Embolden answered 4/9, 2013 at 7:36 Comment(11)
I second that. It also shows the intention of the developer when creating the class so that when getting back to the code, you will think twice before adding a setter which could have dramatic consequences.Bookout
Since it is a member of class,Private fields can have access in other places with in the class.Is it not to prevent like that condition?Brenza
@sᴜʀᴇsʜᴀᴛᴛᴀ Can you rephrase? Making it private means you don't have to read any other class files at least. Note: nested classes can change private fields in the same outer class.Embolden
@PeterLawrey Sorry for my bad English ,But not providing a public setter alone make it as a Immutable class ?? No need to make the field final(other than what you said,about the readability) ?Brenza
@sᴜʀᴇsʜᴀᴛᴛᴀ See the example I added.Embolden
@PeterLawrey Yup.Already going through it. Thanks for the infos :) So you are telling in the last lines that,It should prevent the other methods also to modify it,Am I making myself clear ?Brenza
[Blatant self promoting warning] if you're worried about your immutable class accidentally being made mutable, check out mutabilitydetector.orgCarrero
I think your answer would be much more comprehensive if you referenced the fact that adding final to fields means the Java Memory Model guarantees they're visible immediately. Without it, you have to ensure you're object is safely published across threads yourself.Carrero
@Carrero This is only a concern if you pass it between threads without using write/read memory barriers. e.g. if you use a volatile, AtomicReference, thread safe collection or synchronized, you won't have a problem. You really have to go a ut of your way to see this issue. ;)Embolden
Aren't using volatile, AtomicReference, etc. just various mechanisms for safely publishing, of which final is an often more convenient way? Does final have the downside of incurring extra, potentially unnecessary costs of read/write? Still seems like worth a mention to me. P.S. I was at your talk at DevoxxUk, your experience definitely trumps mine :)Carrero
@Carrero You are right, but the problem is much harder to see than you might think at first.Embolden
X
4

The main reason (IMHO) is that when field is final is guaranteed to be visible in other threads immediately after constructor is finished.

Xiphisternum answered 4/9, 2013 at 7:42 Comment(1)
That is true , as per JMMJabe
B
3
  • Keeping the field final emphasizes the fact that it cannot be changed anywhere else.
  • Self documenting code the the field should not be changed
  • Compiler will help you by giving error if you change the field somewhere else

So final helps in many ways for making object Immutable.

Belmonte answered 4/9, 2013 at 7:41 Comment(0)
W
1

It's good practice to make immutable fields final, even on otherwise mutable objects.

Note that private fields of one object in fact CAN be accessed by other instances of the same class.

An object (class or instance) is immutable, if its internal state cannot be changed (reflection doesn't count). Making a field final guarantees only that the value (if it's a primitive) or reference (for non-primitives) cannot be changed.
For non-primitives, this doesn't automatically mean that the referenced value is also immutable. Which means that if your final field references, for example, a list, one cannot exchange the list, but add/remove values from it, thus changing the state of the object.

For an object to be immutable:

  • The internal state must be determined upon construction and can never change
  • This means all fields that define the state must be final (you may have other helper fields which don't belong to the state, that's ok but rare).
  • This also means that all refernced objects must be immutable. Some objects such as String are already immutable, others such as collections can be wrapped to make them immutable (Collections.immutableList|Set|Collection|...)
Weakwilled answered 4/9, 2013 at 8:0 Comment(2)
It may be good to clarify that there are three kinds of references a mutable object can hold: (1) a reference that encapsulates identity rather than state, (2) a freely-sharable reference to an immutable object, or (3) a reference to an object which would be mutable except that the reference will never be exposed to code that might mutate it. Note that there's no requirement that the first kind of reference identify a mutable object; most usage cases would require that it not do so.Clayclaybank
Reference objects stored as state do not need to be immutable provided they are private, are initialized via deep copy, and only deep copies are returned by getters.Algae
I
0

Making primitive types final ensures immutability. However making non primitive objects final sometimes makes no sense since final object states can be mutated.As Greg points out this depends on the type of Object in question

As the example you showed, all properties are primitive hence final keword make sense.

Insurgent answered 4/9, 2013 at 7:38 Comment(2)
That depends on the object.Sigvard
When designing an immutable object, this is why all mutable data passed in to constructors or returned by getters are done with deep copying. There's still value in marking the fields final because it simplifies maintenance, as Peter Lawrey describes in his answer.Algae
P
0

One benifit of declaring a field final is that it allows compiler to detect attempts to change the field during refactoring. A class can be immutable even if its fields are not final.

Plunder answered 4/9, 2013 at 7:53 Comment(0)
E
0

JVM guarantees that final fields of a class will be initialized before any thread gets hold of the object. Without this guarantee, a reference to an object may be published, i.e. become visible, to another thread before all the fields of this object are initialized, due to reorderings or other optimizations. This could cause racy access to these fields.

This is why, when creating an immutable object, you should always make all its fields final, even if they are not accessible via getter methods.

Ethno answered 20/6, 2022 at 18:51 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.