Diferencia entre final y efectivamente final
Estoy jugando con lambdas en Java 8 y encontré una advertencia local variables referenced from a lambda expression must be final or effectively final
. Sé que cuando uso variables dentro de una clase anónima, deben ser finales en la clase externa, pero aún así, ¿cuál es la diferencia entre final y efectivamente final ?
... a partir de Java SE 8, una clase local puede acceder a variables locales y parámetros del bloque adjunto que son finales o efectivamente finales. Una variable o parámetro cuyo valor nunca cambia después de su inicialización es efectivamente final.
Por ejemplo, supongamos que la variable numberLength
no se declara final y agrega la declaración de asignación marcada en el 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;
}
...
}
...
}
Debido a esta declaración de asignación, la variable numberLength ya no es definitiva. Como resultado, el compilador de Java genera un mensaje de error similar a "las variables locales a las que se hace referencia desde una clase interna deben ser finales o efectivamente finales" donde la clase interna PhoneNumber intenta acceder a la variable numberLength:
http://codeinventions.blogspot.in/2014/07/difference-between-final-and.html
http://docs.oracle.com/javase/tutorial/java/javaOO/localclasses.html
Creo que la forma más sencilla de explicar "efectivamente final" es imaginar agregar el final
modificador a una declaración de variable. Si con este cambio el programa continúa comportándose de la misma manera, tanto en tiempo de compilación como en tiempo de ejecución, entonces esa variable es efectivamente final.
Esta variable a continuación es final , por lo que no podemos cambiar su valor una vez inicializada. Si lo intentamos obtendremos un error de compilación...
final int variable = 123;
Pero si creamos una variable como esta, podemos cambiar su valor...
int variable = 123;
variable = 456;
Pero en Java 8 , todas las variables son finales de forma predeterminada. Pero la existencia de la segunda línea en el código la hace no definitiva . Entonces, si eliminamos la segunda línea del código anterior, nuestra variable ahora es "efectivamente final" ...
int variable = 123;
Entonces... Cualquier variable que se asigne una vez y sólo una vez es "efectivamente final" .
Según los documentos :
Una variable o parámetro cuyo valor nunca cambia después de su inicialización es efectivamente final.
Básicamente, si el compilador encuentra que una variable no aparece en asignaciones fuera de su inicialización, entonces la variable se considera efectivamente final .
Por ejemplo, considere alguna clase:
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;
}
}