Why isn't it possible to access static final fields from a corresponding static initializer using the declaring class as qualifier (in a static way)?
At first, I thought this was an Eclipse bug:
I also consisted some lack of knowledge, because static initializers are not my everyday business. But lo and behold, this works without the class qualifier as expected:
To complete my test series, I gave it a try in the bash:
causing the same result.
This leads me to the final question:
Is there any reason to prohibit the class qualifier when accessing static final fields from static initializer blocks?
Because the declaring class wasn't initialized before?
Actually, you can initialize a static field from a static initializer.
But I think (I'm not sure), you are having another problem. The problem here is that you're (according to the compiler) trying to assign a final field. However, your true intention is not to assign it.. you're trying to initialize it. But the compiler doesn't get this.
When you call something like Test.I the compiler will think you are trying to modify a static variable that it may be previously initialized (i.e. from a static initializer). The compiler is not that smart to see that you're actually initializing your variable, it's just interpreting you're assigning a static variable from a class, be it Test or be it Foo.
However, if you call it without the class qualifier, the compiler knows that you're trying to modify your own static variable, and in a static initializer, so the operation is safe for the final field.
Please, I hope I'm being clear enough, and please, be noted that I'm not sure about this behaviour.
In order to initialise a final variable in a initialization block, the simple name of the variable should be use. i.e. the variable name alone with out any qualifiers.
It is stated on the java language specification as below
"Similarly, every blank final variable must be assigned at most once; it must be definitely unassigned when an assignment to it occurs. Such an assignment is defined to occur if and only if either the simple name of the variable, or its simple name qualified by this, occurs on the left hand side of an assignment operator. A Java compiler must carry out a specific conservative flow analysis to make sure that, for every assignment to a blank final variable, the variable is definitely unassigned before the assignment; otherwise a compile-time error must occur."
Related
Consider the following code snippet in Java. It won't compile.
package temppkg;
final public class Main
{
private String x;
private int y;
private void show()
{
String z;
int a;
System.out.println(x.toString()); // Causes a NullPointerException but doesn't issue a compiler error.
System.out.println(y); // Works fine displaying its default value which is zero.
System.out.println(z.toString()); // Causes a compile-time error - variable z might not have been initialized.
System.out.println(a); // Causes a compile-time error - variable a might not have been initialized.
}
public static void main(String []args)
{
new Main().show();
}
}
Why do the class members (x and y) declared in the above code snippet not issue any compile-time error even though they are not explicitly initialized and only local variables are required to be initialized?
When in doubt, check the Java Language Specification (JLS).
In the introduction you'll find:
Chapter 16 describes the precise way in which the language ensures
that local variables are definitely set before use. While all other
variables are automatically initialized to a default value, the Java
programming language does not automatically initialize local variables
in order to avoid masking programming errors.
The first paragraph of chapter 16 states,
Each local variable and every blank final field must have a definitely
assigned value when any access of its value occurs....A Java compiler
must carry out a specific conservative flow analysis to make sure
that, for every access of a local variable or blank final field f, f
is definitely assigned before the access; otherwise a compile-time
error must occur.
The default values themselves are in section 4.12.5. The section opens with:
Each class variable, instance variable, or array component is
initialized with a default value when it is created.
...and then goes on to list all the default values.
The JLS is really not that hard to understand and I've found myself using it more and more to understand why Java does what it does...after all, it's the Java bible!
Why would they issue a compile warning?, as instance variables String will get a default value of null, and int will get a default value of 0.
The compiler has no way to know that x.toString(), will cause a runtime exception, because the value of null is not actually set till after runtime.
In general the compiler couldn't know for sure if a class member has or has not been initialized before. For example, you could have a setter method that sets the value for a class member, and another method which accesses that member. The compiler can't issue a warning when accessing that variable because it can't know whether the setter has been called before or not.
I agree that in this case (the member is private and there is no single method that writes the variable) it seems it could raise a warning from the compiler. Well, in fact you are still not sure that the variable has not been initialized since it could have been accessed via reflexion.
Thins are much easier with local variables, since they can't be accessed from outside the method, nor even via reflexion (afaik, please correct me if wrong), so the compiler can be a bit more helpful and warn us of uninitialized variables.
I hope this answer helps you :)
Class members could have been initialized elsewhere in your code, so the compiler can't see if they were initialized at compilation time.
Member variables are automatically initialized to their default values when you construct (instantiate) an object. That holds true even when you have manually initialized them, they will be initialized to default values first and then to the values you supplied.
This is a little little lengthy article but it explains it: Object initialization in Java
Whereas for the local variables (ones that are declared inside a method) are not initialized automatically, which means you have to do it manually, even if you want them to have their default values.
You can see what the default values are for variables with different data types here.
The default value for the reference type variables is null. That's why it's throwing NullPointerException on the following:
System.out.println(x.toString()); // Causes a NullPointerException but doesn't issue a compiler error.
In the following case, the compiler is smart enough to know that the variable is not initialized yet (because it's local and you haven't initialized it), that's why compilation issue:
System.out.println(z.toString()); // "Cuases a compile-time error - variable z might not have been initialized.
In the following code, the lambda expressions capture a static variable.
However, it is also local to the scope of the enclosing class, so would this be local variable capture or static variable capture?
public class ExampleImpl{
static String someStaticVar = "text";
Example lam = () -> {
System.out.println(someStaticVar);
};
interface Example {
void sample();
}
}
The terms “local variable capture” and “static variable capture” do not appear anywhere in the specification, so their meaning would be up to whoever coined these terms.
The most likely interpretation is that “local variable capture” just mean “capture of a local variable” and likewise “static variable capture” means “capture of a static variable”, in other words, capture of a variable which happens to be of either kind, local, instance field, or static field, and then, the answer is quiet simple, the nature of the variables doesn’t change when you place a lambda expression in a different scope.
In your example, someStaticVar always is a static variable, regardless of where you access it.
It’s not clear why this distinction matters to you. There might be technical differences under the hood, which are intentionally unspecified, hence, implementation specific. The most relevant aspect of the type of the captured variables would be that capturing an instance variable will cause the generated instance to keep a reference to the instance. But first, this doesn’t apply to local variables or static variables, second, this is a natural relationship, that code potentially accessing an instance field may prevent the garbage collection of that instance.
I know that static variables are common for all instances and instance variables can be different for different variables. But, when I initialize a static variable in a constructor, the static variable can be different for different instances. Why doesn't Java give me an error when I do this?What is the point of static variables if it changes when I initialize it in a constructor?
Updating the value of the static variable in a constructor can make sense in some scenarios.
The first example I can think of is a static counter variable that counts the number of instances created for a given class. You'd increment that variable inside the constructor.
public class SomeClass
{
private static int instanceCounter = 0;
public SomeClass()
{
...
instanceCounter++;
...
}
}
Another example would be lazy initialization of a static variable. You may want to initialize a static variable only when the first instance of the class is initialized (which means inside a constructor).
Why doesn't Java give me an error when I do this?
Because it is not a Java error. It may be a mistake in your program, but it could also be exactly what is required. The compiler simply has no way of "knowing".
(A compiler that says "error" for something that is not an error is a really bad idea. It only encourages people to turn off the error / warning messages.)
What is the point of static variables if it changes when I initialize it in a constructor?
Static variables can be used for all sorts of things, and some of them include global counters (see #Eran's example) or "most recent" values or state changes. Any of these could be updated in a constructor.
I know how the compiler interprets the final keyword in Java, but how should us programmers interpret its meaning? Should it be:
1) This variable cannot be changed (used by inner class for example)
or
2) I'm not planning to change this variable (might have some optimisation benefits for member variables).
I'm asking because I've worked on code where everything is declared final by default (option 2 above) which, in my opinion, devalues the keyword and hides the values that really can't change! Is there still performance benefits in declaring variables final?
Everything being final by default is a good thing. The more you can model your code on immutability, the easier it tends to be to reason about.
Using final is hardly ever about performance in my opinion. It's about making assertions about the rest of the code (nothing changes this variable) which can help a reader to understand the code, and can be checked by the compiler.
EDIT: The above is my view for fields. For local variables (including parameters) I personally only use final when the variable will be used in an anonymous inner class. This is different from fields because:
It's easy to see the whole context of the method - and if it's not, that's a problem in itself.
As it doesn't represent the state of an object (or class) the benefits of immutability don't really apply.
The final keyword should be abandoned, it should be standard in all applicable cases, and the finality should only be revokable with a keyword like
this_variable_will_change_unexpectedly_behind_your_back
This keyword should not get autocompleted by any IDE, and it shoud not be possible to insert it with Ctrl-V.
I wrote a post about this a while ago.
Final helps reading code:
without the use of final everything may be mutable (potential mess)
it forces setting a variable before it can be used (useful in constructors)
By using final you tell the compiler something about your code and it helps you in return.
The 2nd option is a safeguard. It stops you from accidentally changing or reassigning. As such it's useful to provide and you can remove when you decide you want that variable to change.
I can't add much to what Jon has already said, but just for completeness, JLS 17.5.3 says final fields also may lead to optimizations;
If a final field is initialized to a compile-time constant expression (§15.28) in the field declaration, changes to the final field may not be observed, since uses of that final field are replaced at compile time with the value of the constant expression.
I don't understand why you think there's lack of value.
When I see all final variables, it implies that the class is immutable. That's a good thing, because immutable classes are inherently thread safe.
final variables are a good thing generally speaking. Note that it only means that the variable can't be reassigned, but the object it points to can change if it is mutable.
Performance wise, final allows more aggressive compiler optimisations:
the specification allows aggressive optimization of final fields. Within a thread, it is permissible to reorder reads of a final field with those modifications of a final field that do not take place in the constructor.
Declaring every variable as final is not devaluing final keyword. It helps developers in debugging the application to rule out possibility of modification of variables, especially during multi threaded environment of application.
With java 8 release, we have one more concept called "effectively final variable"
local variables referenced from a lambda expression must be final or effectively final
A variable is considered effective final if it is not modified after initialization in the local block. This means you can now use the local variable without final keyword inside an anonymous class or lambda expression, provided they must be effectively final.
If you don't want to declare effective final as final variable, this new feature helps you if you are using lambda expressions/anonymous classes. You can avoid declaration of final keyword for effective final variables. Have a look at this article
Its true that final variable is used so that no one can change the value, it works as constant in java.
Let me give example
I have created one package which can be used by some other person as well, now there are some configurations variable that are need to set in order to run it properly. lets say its login package. So there can be few encryption options like
encryption_method = HASH_ENCRYPTION
OR
encryption_method = SYMMETRIC_ENCRYPTION
instead of passing integer 1, 2, 3 we can define final variable which helps developer in more readable form and ofcource i don't want user to change it so I keep it final, else internal logic may break
I've just come across some code that's confusing me slightly; there are really 2 variations that I'd like to clarify.
Example 1:
public String getFilepath(){
final File file = new File(this.folder, this.filename);
return file.getAbsolutePath();
}
What would be the purpose of declaring file "final"? Since Java primitives are passed by value, and getAbsolutePath() is just returning a String, the variable won't be final on the other side (calling method), will it? And since the file variable only exists within the scope of these 2 lines, I can't really see any purpose of the final keyword. Is there something I'm missing? Anyone see a reason to do this?
Example 2:
public String getFilepath(){
final File file = new File(this.folder, this.filename);
return file;
}
Since here the actual object is being returned... Does that mean the file variable will be constant/final on the other side...? It doesn't seem to make sense.
In general, it seems to me that you pass a variable, without it's access type. As in, I can have a private variable in a function with a public get function that returns it - but the variable that receives it by calling the function has to specify an access modifier. So if it specifies public, the returned variable will be public in that scope. If it specifies private, the returned variable will be private in that scope. Is there a difference with final? Is the "constancy" of a variable something that can be passed? This strikes me as rather improbable, considering what I know of Java.
Or am I missing the point entirely and there's some other purpose of the final keyword in the above code?
Edit:
I checked back with the original developer who wrote the code, and he said he only put the final keyword in because he had originally thought the method would be a lot longer and wanted to ensure that the file stayed constant throughout. He also said that he generally declares variables that should not be changed as final, as a rule across the board and sort of on principle - a point that both the answers below mentioned. So it seems I was reading too much into a simple extra keyword included for standards reasons. Thanks everyone!
final in this case just means that the local reference file will be immutable. It has no meaning outside the method. Some coding conventions advocate having all variables final unless they need to be mutable so you'll see code like that when someone is following such guidelines.
Some people might tell you that there's a performance benefit to using final, but that is, in no way, conclusively proven.
The primary benefit of the final keyword is for the programmer to indicate that a class, method, or field should not be changed.
Bear in mind that declaring a variable final does not make the referenced object immutable. It just means that the variable cannot have its value reassigned. You can still run methods of the variable file that could change the File object internally.
In the two methods you give, I see no value in making the file variable final. Some code conventions advocate making all variable final unless the need to be modified. Some people don't subscribe to that. I consider it a variation on the precautionary principle.