This question is not primarily about Strings. Out of academic curiosity I would like to know how the final modifier on a variable can change the behaviour a program. The following example shows it is possible.
These lines print true
final String x = "x";
System.out.println(x + x == "xx");
but these lines print false
String x = "x";
System.out.println(x + x == "xx");
Apart from String interning, are there any other things that can cause the behaviour of a program to change if the modifier final is removed from a variable declaration? I am assuming that the program compiles with or without the modifier.
Please don't vote to close it as duplicate of Comparing strings with == which are declared final in Java. I understand the Strings example.
I'm asking if there are any other reasons removing a final modifier can make a difference. Please can someone link to an answer or answer the question. Thanks.
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.
Related
We know that there is a default of each primitive data type in Java(For e.g.:- The default value of double data type is 0.0d.).Then if we want the value of a variable(suppose double a) to be equal to the default value,why should we need to specify the value as:
double a=0.0d;
Why can't we not just use the default value of the variable anywhere as its default value is the same as the value we want to assign?
Different types do have default values that will be assigned to any unassigned fields of that type. However, this does not apply to local variables, as shown in the Language Specification §4.12.5:
A local variable (§14.4, §14.14) must be explicitly given a value
before it is used, by either initialization (§14.4) or assignment
(§15.26), in a way that can be verified using the rules for definite
assignment (§16 (Definite Assignment)).
I speculate that this is to make your code clearer. In a method, you would want readers of your code know what each and every variable's value is, instead of relying on the reader remembering facts like "a booleans default value is false". Since what you are writing is likely an algorithm of some sort, you want to write it as clearly as possible for other people.
In fields however, this is not required. I think this is because you are not describing a set of steps to do something. Instead, you are just saying that this object has some property. The semantics are a little different here.
As per Java language specification local variable must be initilized before use. Let's see why would such rule would have been made for local variables and not for instance variables.
Compiler tries to eliminate as much errors as possible during compile time only thereby making the application runtime more stable. For this it detects the issues it can at compile time and throws compile time exceptions.
Non final instance variables can be initilized in constructor (which may be multiple, overloaded) or in one of the methods of the class. Before using such a variable compiler does not complain as it assumes programmer would have provided the initial value in some method or constructor. The initilization depends on run time of the application as during run time a method can be invoked which does the initilization and hence compile time detection if value is not provided by the programmer is not possible and hence compiler chooses the safe option of allowing usuage and provides the default value in case method or constructor which handles the initilization is not invoked.
Non final local variable can only be initilized within it's method. There is not much point of making a non final variable if user wants to use the default value. It makes more sense to use the value directly or use a final keyword. If a non final local variable has been used then compiler forces the user to provide the initial value which may or may not be the default value.
For final fields both instance level and local, compiler forces the user to provide the initial value.
You need to initialise only local variables or class level variables declared final as per the java language spec. They won't be initialised with default values.
I know that:
A blank final class variable must be definitely assigned by a static initializer of the class in which it is declared, or a compile-time error occurs.
A blank final instance variable must be definitely assigned at the end of every
constructor of the class in which it is declared, or a compile-time error occurs.
Why final variable cannot be assigned just once at any time instead of just at declare time?
The corollary to this, for non-final variables, is the initial value of a variable. Every field receives an initial value depending on its type - usually a variant of 0 or null.
It's implied here that, if you're declaring a variable to be final, then you have a specific value in mind that you wish that variable to be assigned and not have changed later in its run. Java doesn't know what value that is, and it likely takes away the convenience of automatically declaring those values for you so to not interfere with the developer's intentions.
That and requiring that all final variables be initialized is to support all variables being definitely assigned before their use. You can use a non-final field that you don't initialize to some value - it'll likely be null though - but you can't use a local variable that you haven't initialized yet for the same reason.
First it is not something against null. The following is legal too:
final String ABC;
{
ABC = null;
}
static final String DEF;
static {
DEF = null:
}
final String GHI = null;
It was the following decision:
When a final field or a local variable is not initialized it can very
well be a bug, forgetting to initialize.
(For normal fields it would be too much boiler code, and zeroing of fields is provided.)
For local variables you might find this obvious. As final variables can only be assigned once, and it was decided that this should happen only during construction (otherwise you would need administration of whether the variable was initialized).
Language design decisions are always a trade off between flexibility and error prevention. In this case, there are some simple questions to check:
In case, there is a code path in which a final variable is not assigned:
How likely is it that the developer declares a final variable just to hold the default value, null, 0 or false?
In contrast, how likely is it that the developer has forgotten the initialization or overlooked a possible code path, in other words, rejecting this code prevents a nasty bug?
How much work is it for the developer, to write the explicit assignment, if (s)he really wants the default value?
I think, trying to answer these questions should lead to the rationale behind this design decision.
This is the place for an important clarification. In case of local variables, all variables must be initialized before use. The restriction is only lifted for non-final heap variables, read, fields and array elements.
In case of arrays, it should be obvious why developers are not enforced to write explicit default values when arrays can be instantiated for lengths up to 2³¹ elements. For non-final instance fields, this decision can be discussed. But such a discussion would be outside the scope of Stackoverflow…
Constants (final) of primitive types should be written in CAPITAL_LETTERS. But what about a class instance? For example, when it is passed as a function parameter, is called from inner class and should be declared final. Are all parameters supposed to be final? Should it be this way then:
public static void myFunction(
final MyClass CLASS_INSTANCE) {
// Code.
}
CAPITAL_LETTERS... What about a class instance?
Nope. That would be weird. Parameters use camel case. The fact that something is final doesn't affect conventions around case.
Are all parameters supposed to be final?
No. Declare things final if they shouldn't ever change. That often applies to a parameter, but not always.
Declaring something final does two things: it helps pick up bugs where something never gets initialised or can be changed after initialisation; and it acts as a hint to the compiler to allow some optimisations.
No, final parameters should not be written in all-uppercase -- they're not constants.
The terms constant and final are not synonymous.
Uppercase is indeed used for constants, as specified by early Java naming conventions.
The names of variables declared class constants and of ANSI constants should be all uppercase with words separated by underscores ("_").
But not all variables declared final are constants. From the Java language specification, section 4.12.4, "Final variables":
A constant variable is a final variable of primitive type or type String that is initialized with a constant expression (§15.28).
Parameters are not constants. They're not initialized with a constant expression. And in your example, the parameter is not a primitive type or String.
Therefore, parameters are specified in mixed case, with an initial lowercase first letter.
To start with a nitpick: Java does not really have constants. It has final static variables, which -- for all intents and purposes -- often behave like constants. But they behave differently (and unexpectedly) in some rare situations, even when they have a primitive type.
Anyway, by convention, variables which behave like constants are given name in capitals. For example, java.awt.Color defines constants RED and BLUE of type Color. (It also defines constants red and blue, but since RED and BLUE were added later, I suspect the Sun/Oracle people considered those names a mistake.)
But parameters are not constants and do not behave like them. For every method invocation they can have a different value. Thus parameters are always named in camel case, even if they are declared final.
And should parameters be declared final? When, here is where convention stops and mere taste begins. Some people say yes, some people say no. I belong to the "no" camp. Making a parameter final could help prevent introducing bugs by giving a compiler error if you try to modify it. However, if your method body is so long that you actually require this help, then your method should probably be refactored. On the other side, I find parameter lists without final keywords everywhere easier to read and clearer, so I tend to leave them out.
What is difference between Fields and Constants in android documentations?
For example in View Class we have Fields and Constants.Whiles, I think that the Constants in View Class are Fields. Because each variable in each class is Field. Please example for me about this ambiguity.
When your app is compiled, any constant values are compiled directly into the application. Using an example from #CommonsWare's comment, ACCESSIBILITY_LIVE_REGION_ASSERTIVE is an integer with the value 2. That value will continue to be used by your app even if the View class is updated in a future release of Android, which is why you can't put "what version of Android am I currently running on" in a constant. Conversely, it's a fine way to record which version of the SDK your app was compiled against.
The fields are final, which means you can't change them, unless you use JNI, in which case you can. However, because the compiler uses the values directly whenever possible, changing the value of the final fields won't affect any code -- unless it accesses them through reflection.
So the distinction between "constant" and "field" may be of importance.
Primitive types and Strings may be constants. For arrays and other object types, such as the int[] used for SELECTED_STATE_SET, the reference itself is read-only, but the contents of the object are not. This is true of any mutable object type, so it doesn't make sense to list them under "constants".
There is no such thing as a Constant in Java. There are only fields which you can mark static to became a class field (i.e. one instance per class, for all objects of the same class, rather than one per each object, as if without "static"). You can access static fields by class name reference, without instantiating the class (i.e. MyClassName.sMyStaticField)
Furthermore, you can mark your field final. That means the field value assigned in initialization code and will never change. If you are assigning to static final field a constant value (for example, a number), this value will be unchanged and the same for all class instances. So, in Java it is used as a constant value, to assign a particular value to a particular name.
Since their values are known at a compile time, they can be used to make conditional compilation. Part of your code, depending on such constant values, could be excluded at a compile time
public static final boolean ENABLE_MY_SUPER_DUPER = false;
...
if (ENABLE_MY_SUPER_DUPER) {
doSuperDuper(); // Not just never executed, but not even compiled
}
That's cannot be happened, if value assigned to a field could not be known at a runtime (for example, references to objects, or arrays)
So, technically, static final fields and so called "constants" is the same, but in documentation "constants" denotes some predefined constant values, that the same for all applications (i.e. numbers, string constants etc.).
While in "field" under "static final" there are some objects, which are instantiated once just after application starts, but it's value cannot be known at a compile time. For example, arrays, some object instances, etc.
Technically you cannot alter their values, since they are finals, but you can alter their internal content. I.e. you cannot create new object or array and assign it to the same field, but you can alter items or fields of already created array/object.
Had same doubt though got the correct answer. In ViewGroup.LayoutParams class there are three constants and three fields
Constants :
int WRAP_CONTENT
int FILL_PARENT
int MATCH_CONTENT
Fields :
public int height
public layoutAnimationParameters
public int width
the difference can be seen in the source code of android
https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/view/ViewGroup.java#7857
here we see
public static final int FILL_PARENT = -1;
so the constants are nothing but fields which are final
Hope this helps!!
I want to have a file with constants being accessed from multiple threads. Is it a safe implementation to have a class with a lot of public static final ints for this?
Yes, it is thread-safe. Any static final variable is guaranteed to be initialized after class initialization. Thus, once a class containing such a static final variable is used anywhere in your code, it is always fully initialized (i.e. the value is set) by requirement of the JVMS.
With a primitive int, this condition is even tighter. A primitive static final variable (same goes for String) is a so called compile-time constant which are inlined by the Java compiler javac. The only requirement is that the value can be computed by the Java compiler, i.e. it must not be the result of a non-constant evaluation. As you are write that you want to define constants, I assume that this does not apply for your use case. Those constant values are therefore directly copied to their access location what cuts the corner-case of non-thread safety of a static final variable being altered via reflection wich is hypothetically an issue with non-primitive types.
Furthermore, using such variables is a good idea because it avoids the use of so-called magic numbers.
Yes, it is safe.
The value never changes so there is no risk of race conditions. Java guarantees that the value will be initialized before anything tries to use it.
Whether it is the best architecture for other reasons (clarity of design etc) is another question.
Yes, 100% safe. It's final, so nobody can alter it. Every thread has to access as reader only, and there is no contention for reading only.
For primitives, making them final makes them compile time constants (if initialized directly and not as result of method) and an int is a primitive. So, final int makes it immutable and hence thread-safe.