I want to use try-with-resources enhancement in Java 9 by putting reference variable inside try with resources instead of the entire variable declaration. I also know that to do that I must follow rule: Variable used as a try-with-resources resource should be final or effectively final
. First I will try with local and then with instance variable.
-I make variable final, which follows the given rule and compiles fine:
public static void main (String[] args) throws IOException{
final FileWriter fw = new FileWriter ("test.txt");
try(fw) {
//some code
}
}
-If I also removed final keyword, it would again compile as fw
is considered effectively final -variables that are initialized only once and never mutated.
public static void main (String[] args) throws IOException{
FileWriter fw = new FileWriter ("test.txt");
try(fw) {
//some code
}
}
But will this same pattern work for instance variable as well? Let's try.
-First let's make instance variable final, which again follows the rule and compiles fine:
public class Test {
final FileWriter fw = new FileWriter ("a.txt");
void m1() throws IOException {
try(fw ) {
//some code
}
}
}
-If I remove final keyword, it should again compile, should it? As I am not mutating fw
anywhere but initializing it only once - should be effective final. Unfortunatelly, this won't work:
public class Test {
FileWriter fileWriter = new FileWriter ("a.txt");
void m1() throws IOException {
try(fileWriter) {
//some code
}
}
}
It gives me message: Variable used as a try-with-resources resource should be final or effectively final. So after all this, I am coming back to my first question. Can instance variable ever be effectively final or that term is used only for local variables? As I just showed, I am never mutating a variable (which should be considered effectively final), yet compiler never threats it as such.
The Java Language Specification, section 4.12.4. final
Variables, clearly specifies that only local variables and parameters can be effectively final:
Certain variables that are not declared
final
are instead considered effectively final:
A local variable whose declarator has an initializer (§14.4.2) is effectively final if all of the following are true:
It is not declared
final
.It never occurs as the left hand side in an assignment expression (§15.26). (Note that the local variable declarator containing the initializer is not an assignment expression.)
It never occurs as the operand of a prefix or postfix increment or decrement operator (§15.14, §15.15).
A local variable whose declarator lacks an initializer is effectively final if all of the following are true:
It is not declared
final
.Whenever it occurs as the left hand side in an assignment expression, it is definitely unassigned and not definitely assigned before the assignment; that is, it is definitely unassigned and not definitely assigned after the right hand side of the assignment expression (§16 (Definite Assignment)).
It never occurs as the operand of a prefix or postfix increment or decrement operator.
A method, constructor, lambda, or exception parameter (§8.4.1, §8.8.1, §9.4, §15.27.1, §14.20) is treated, for the purpose of determining whether it is effectively final, as a local variable whose declarator has an initializer.
If a variable is effectively final, adding the
final
modifier to its declaration will not introduce any compile-time errors. Conversely, a local variable or parameter that is declaredfinal
in a valid program becomes effectively final if thefinal
modifier is removed.