Java Final Modifier

How does the final keyword in Java work? (I can still modify an object.)

You are always allowed to initialize a final variable. The compiler makes sure that you can do it only once.

Note that calling methods on an object stored in a final variable has nothing to do with the semantics of final. In other words: final is only about the reference itself, and not about the contents of the referenced object.

Java has no concept of object immutability; this is achieved by carefully designing the object, and is a far-from-trivial endeavor.

Using the final modifier whenever applicable in Java

I think it all has to do with good coding style. Of course you can write good, robust programs without using a lot of final modifiers anywhere, but when you think about it...

Adding final to all things which should not change simply narrows down the possibilities that you (or the next programmer, working on your code) will misinterpret or misuse the thought process which resulted in your code. At least it should ring some bells when they now want to change your previously immutable thing.

At first, it kind of looks awkward to see a lot of final keywords in your code, but pretty soon you'll stop noticing the word itself and will simply think, that-thing-will-never-change-from-this-point-on (you can take it from me ;-)

I think it's good practice. I am not using it all the time, but when I can and it makes sense to label something final I'll do it.

Add final modifier at runtime in Java

At certain point I want to prevent changing its value

Do that in application logic. Make the variable only accessible through methods. Keep a flag tracking any change to the variable. After you've applied the change or reached the certain point, raise the flag, and throw an exception for any further attempts at changing the variable.

final is a language keyword/feature for writing your source code and preventing re-assignment of a variable in source code. At runtime, it does (almost) nothing.

Java final modifier

Answering each of your points in turn:

primitive variables: can be set only once. (memory and performance gain)

Yes, but no memory gain, and no performance gain. (Your supposed performance gain comes from setting only once ... not from final.)

objects variables: may be modified, final applies to object reference.

Yes. (However, this description miss the point that this is entirely consistent with the way that the rest of the Java language deals with the object / reference duality. For instance, when objects are passed as parameters and returned as results.)

fields: can be set only once.

The real answer is: same as for variables.

methods: can't be overridden, hidden.

Yes. But also note that what is going on here is that the final keyword is being used in a different syntactic context to mean something different to final for an field / variable.

classes: can't be extended.

Yes. But also see note above.

garbage collection: will force Java generational garbage collection mark-sweep to double sweep.

This is nonsense. The final keyword has no relevance whatsoever to garbage collection. You might be confusing final with finalization ... they are unrelated.

But even finalizers don't force an extra sweep. What happens is that an object that needs finalization is set on one side until the main GC finishes. The GC then runs the finalize method on the object and sets its flag ... and continues. The next time the GC runs, the object is treated as a normal object:

  • if it is reachable it is marked and copied
  • if it is not reachable it is not marked.

(Your characterization - "Java generational garbage collection mark-sweep" is garbled. A garbage collector can be either "mark-sweep" OR "generational" (a subclass of "copying"). It can't be both. Java normally uses generational collection, and only falls back to mark-sweep in emergencies; i.e. when running out of space or when a low pause collector cannot keep up.)

Can make clone fail (this is both good and bad)

I don't think so.

Can make immutable primitives aka const

Yes.

Can make blank immutable - initialized at creation aka readonly

Yes ... though I've never heard the term "blank immutable" used before.

Can make objects shallowly immutable

Object mutability is about whether observable state may change. As such, declaring attributes final may or may not make the object behave as immutable. Besides the notion of "shallowly immutable" is not well defined, not least because the notion of what "shallow" is cannot be mapped without deep knowledge of the class semantics.

(To be clear, the mutability of variables / fields is a well defined concept in the context of the JLS. It is just the concept of mutability of objects that is undefined from the perspective of the JLS.)

Can make scope / visibility immutable

Terminology error. Mutability is about object state. Visibility and scope are not.

Can make method invocation overhead smaller (because it does not need virtual table)

In practice, this is irrelevant. A modern JIT compiler does this optimization for non-final methods too, if they are not overridden by any class that the application actually uses. (Clever stuff happens ...)

Can make method arguments used as final (even if thy are not)

Huh? I cannot parse this sentence.

Can make objects threadsafe

In certain situations yes.

(if object is defined as final, it wont make method arguments final)

Yes, if you mean if class is final. Objects are not final.

Can make mock tests (not that you could do anything about it - you can say bugs are intended)

Doesn't parse.

Can't make friends (mutable with other friends and immutable for rest)

Java doesn't have "friends".

Can't make mutable that is changed to be immutable later (but can with factory pattern like fix)

Yes to the first, a final field can't be switched from mutable to immutable.

It is unclear what you mean by the second part. It is true that you can use a factory (or builder) pattern to construct immutable objects. However, if you use final for the object fields at no point will the object be mutable.

Alternatively, you can implement immutable objects that use non-final fields to represent immutable state, and you can design the API so that you can "flip a switch" to make a previously mutable object immutable from now onwards. But if you take this approach, you need to be a lot more careful with synchronization ... if your objects need to be thread-safe.

Can't make array elements immutable aka deeply immutable

Yes, but your terminology is broken; see comment above about "shallow mutability".

Can't make new instances of object (this is both good and bad)

No. There's nothing stopping you making a new instance of an object with final fields or a final class or final methods.

Can't make serialization work

No. Serialization works. (Granted, deserialization of final fields using a custom readObject method presents problems ... though you can work around them using reflection hacks.)

There are no alternatives to final,

Correct.

but there is wrapper + private

Yes, modulo that (strictly speaking) an unsynchronized getter for a non-final field may be non-thread-safe ... even if it is initialized during object construction and then never changed!

and enums.

Solves a different problem. And enums can be mutable.

final keyword in method parameters

Java always makes a copy of parameters before sending them to methods. This means the final doesn't mean any difference for the calling code. This only means that inside the method the variables can not be reassigned.

Note that if you have a final object, you can still change the attributes of the object. This is because objects in Java really are pointers to objects. And only the pointer is copied (and will be final in your method), not the actual object.

cheat with java final keyword

Fields don't have to be final to be accessed from anonymous classes, just method variables.

This is because field (of its entity or class) exists until it is no longer needed (determined by GC), so there's always a place where you can assign.

However, if you're passing anonymous class instance somewhere, it might still exist when containing method has exited. Imagine otherAction invoking this listener sowetime in distant future. But there's nowhere to assign this variable anymore, hence it should be final and copied on anynomous class instantiation.

How can removing final keyword change the way a program behaves?

The final modifier only ensures that the variable is definitely assigned, and prohibits any reassignment to and from that variable.

The only special cases that can be observed are expressly stated in the JLS:

A variable of primitive type or type String, that is final and initialized with a compile-time constant expression (§15.28), is called a constant variable.

Whether a variable is a constant variable or not may have implications with respect to class initialization (§12.4.1), binary compatibility (§13.1, §13.4.9) and definite assignment (§16).

There's a decent amount of JLS reading, and to cover the main point: By JLS §13.4.9, you will not encounter any ill effects upon removing the final modifier.

However, by JLS 17.5, if you rely on the guarantee of a thread only seeing the definitely assigned variables in an object that it can observe, then removing the final variable will cause those variables to no longer be visible to another thread.


So, if we look at class initialization first, there are rules surrounding class initialization if the field is static and not a constant variable:

A class or interface type T will be initialized immediately before the first occurrence of any one of the following:

  • T is a class and an instance of T is created.
  • T is a class and a static method declared by T is invoked.
  • A static field declared by T is assigned.
  • A static field declared by T is used and the field is not a constant variable (§4.12.4).

In JLS §13.1, it is spelled out that changing a field to final can break binary compatibility:

References to fields that are constant variables (§4.12.4) are resolved at compile time to the constant value that is denoted. No reference to such a field should be present in the code in a binary file (except in the class or interface containing the field, which will have code to initialize it). Such a field must always appear to have been initialized (§12.4.2); the default initial value for the type of such a field must never be observed. See §13.4.9 for a discussion.

From 13.4.9:

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

Deleting the keyword final or changing the value to which a field is
initialized does not break compatibility with existing binaries.

If a field is a constant variable (§4.12.4), then deleting the keyword
final or changing its value will not break compatibility with
pre-existing binaries by causing them not to run, but they will not
see any new value for the usage of the field unless they are
recompiled. This is true even if the usage itself is not a
compile-time constant expression (§15.28).

This result is a side-effect of the decision to support conditional
compilation, as discussed at the end of §14.21.

So from that alone, be careful about suddenly changing fields to final. Removing the field is safe.

...but that only applies to a single-threaded world. From JLS 17.5:

Fields declared final are initialized once, but never changed under
normal circumstances. The detailed semantics of final fields are
somewhat different from those of normal fields. In particular,
compilers have a great deal of freedom to move reads of final fields
across synchronization barriers and calls to arbitrary or unknown
methods. Correspondingly, compilers are allowed to keep the value of a
final field cached in a register and not reload it from memory in
situations where a non-final field would have to be reloaded.

final fields also allow programmers to implement thread-safe immutable
objects without synchronization. A thread-safe immutable object is
seen as immutable by all threads, even if a data race is used to pass
references to the immutable object between threads. This can provide
safety guarantees against misuse of an immutable class by incorrect or
malicious code. final fields must be used correctly to provide a
guarantee of immutability.

An object is considered to be completely initialized when its
constructor finishes. A thread that can only see a reference to an
object after that object has been completely initialized is guaranteed
to see the correctly initialized values for that object's final
fields.

So, if your program relies on the above guarantee for it to function normally, then removing the final keyword will have consequences in threading.

Using final in method parameters in Java

  1. Using final modifier on method parameters doesn't make much sense
    since it adds visual clutter to the method declaration without
    buying you much. As far as you can make sure that you don't reassign
    values to those variables, you are good enough to go without final
    modifier on method parameters.
  2. Method parameters lie on the stack, and it is local to that
    particular thread as far as that thread doesn't publish it to some
    other thread. Since it is not shared between the other threads, no
    thread safety issue arises here. However, if the current thread
    publishes these arguments, then you are out of luck and the use of
    final modifier doesn't give you any thread safety guarantee.

Here's one such a tasteful use of final modifier to write an immutable class which represents a point in our 2-dimensional space.

class Point2D {
private final int x;
private final int y;

Point2D(int x, int y) {
this.x = x;
this.y = y;
}

// Remainder omitted for brevity's sake !
}

Once this class instance is created, you can share it freely with other threads and you don't need to bother synchronizing access to it's state. So, immutable objects give you thread safety for free.

You may read JLS § 17.5 for more details on semantics of final fields.

Does it make sense that I have to make most of my variables final?

If one were to redesign Java today variables should probably default to private and final rather than package and mutable.

Mutable variables are sometimes necessary but whenever possible you should prefer final, and I can't really think of many legitimate reasons to make variables anything but private.

Things might be different for different target environments but Java is designed to make good readable/maintainable long-lived code, and considering this they just made a few poor decisions on defaults.

But it's an old language and we didn't know as much as we do now. live and learn.

ps: I'd also throw out checked exceptions if I was in charge... probably a good thing I'm not.



Related Topics



Leave a reply



Submit