The final keyword in java has a wide scope of usage. It can be used with:
- classes - public final class Foo {...}
- methods - public final void Bar() {...}
- member variables - private final int a;
- local variables - final int xMin = 2;
In generally the final keyword makes the corresponding class/method/variable immutable.
For classes and methods immutability means that it can not be specialized respectively overridden, whereas for variables it means that after the initialization, their value can not be changed.
Java does not make any analysis of your classes, so member variables declares as final must be initialized in the constructor of the corresponding class. After the initialization, their value is freeze.
Consider the following snippet:
1: public class Foo {
2: protected final int xMin;
3: protected final int xMax = 10;
4:
5: public Foo() {
6: xMin = 5;
7: xMax = 10; // This is of course a compiler error
8: }
9: }
10:
11: public class Bar extends Foo {
12: public Bar() {
13: super():
14: xMax = 15; // Compiler error
15: }
16: }
I used to use final really intensive in my code, for two reason:
- it reduces the possible states of a class
- it makes multithreading a lot easier
The possible states of a class are reduced, since the amount of its members that might change (put the class in a different state) is reduced. It makes much more easier to understand, but also to test your classes. Further more, it reduces the possibility of failures. I saw an extreme example, how bad it can come.
If you use final, it is good to know how it really works. Consider the following snippet:
1: public class Foo {
2: private final List<String> names = new ArrayList<String>();
3: public void addName(String name) {
4: names.add(name); // this gonna work
5: }
6: public void releaseList() {
7: names = null; // compiler error
8: }
9: }
If you go further it is even meaningful to use immutable variables in a method. These provides some hints on your intentions, and might help in the future if you need change the method or fix bugs.
Now, let's consider the impacts of immutability on multithreading:
One of the most difficult things about writing concurrent programs is deciding how to protect mutable shared state. Java provides a locking primitive,
synchronized
, but locking primitives are difficult to use. You have to worry about- data corruption (if you lock too little)
- deadlock (if you lock too much)
- performance degradation (even if you get it right)
Using immutable objects, you don't need to take care about synchronization. Functional languages, such as SCALA do enforce immutability, and are really powerful in multithreaded applications.