Difference between final and effectively final
I'm playing with lambdas in Java 8 and I came across warning local variables referenced from a lambda expression must be final or effectively final
. I know that when I use variables inside anonymous class they must be final in outer class, but still - what is the difference between final and effectively final?
Solution 1:
... starting in Java SE 8, a local class can access local variables and parameters of the enclosing block that are final or effectively final. A variable or parameter whose value is never changed after it is initialized is effectively final.
For example, suppose that the variable numberLength
is not declared final, and you add the marked assignment statement in the PhoneNumber
constructor:
public class OutterClass {
int numberLength; // <== not *final*
class PhoneNumber {
PhoneNumber(String phoneNumber) {
numberLength = 7; // <== assignment to numberLength
String currentNumber = phoneNumber.replaceAll(
regularExpression, "");
if (currentNumber.length() == numberLength)
formattedPhoneNumber = currentNumber;
else
formattedPhoneNumber = null;
}
...
}
...
}
Because of this assignment statement, the variable numberLength is not effectively final anymore. As a result, the Java compiler generates an error message similar to "local variables referenced from an inner class must be final or effectively final" where the inner class PhoneNumber tries to access the numberLength variable:
http://codeinventions.blogspot.in/2014/07/difference-between-final-and.html
http://docs.oracle.com/javase/tutorial/java/javaOO/localclasses.html
Solution 2:
I find the simplest way to explain "effectively final" is to imagine adding the final
modifier to a variable declaration. If, with this change, the program continues to behave in the same way, both at compile time and at run time, then that variable is effectively final.
Solution 3:
According to the docs:
A variable or parameter whose value is never changed after it is initialized is effectively final.
Basically, if the compiler finds a variable does not appear in assignments outside of its initialization, then the variable is considered effectively final.
For example, consider some class:
public class Foo {
public void baz(int bar) {
// While the next line is commented, bar is effectively final
// and while it is uncommented, the assignment means it is not
// effectively final.
// bar = 2;
}
}
Solution 4:
This variable below is final, so we can't change it's value once initialised. If we try to we'll get a compilation error...
final int variable = 123;
But if we create a variable like this, we can change it's value...
int variable = 123;
variable = 456;
But in Java 8, all variables are final by default. But the existence of the 2nd line in the code makes it non-final. So if we remove the 2nd line from the above code, our variable is now "effectively final"...
int variable = 123;
So.. Any variable that is assigned once and only once, is "effectively final".