que - Java dejó de cometer errores en variables no finales en clases internas(java 8)
que clases internas no llevan nombre (4)
Esta pregunta ya tiene una respuesta aquí:
- Diferencia entre final y efectivamente 13 respuestas finales
Java 7 estaba diciendo "No se puede referir al mensaje de variable local no final definido en un ámbito adjunto" en el siguiente código:
public class Runner {
public static void main(String[] args) {
String message = "Hello world";
new Runnable() {
@Override
public void run() {
System.out.println(message);
}
}.run();
}
}
Java 8 no lo hace.
Sospecho que esto se trata de agregar características de programación funcional a Java.
¿Procesa el código de manera similar?
El message
variable es efectivamente final . Citar de referencia de idioma
Si una variable es efectivamente final, agregar el modificador final a su declaración no introducirá ningún error en tiempo de compilación.
Por lo tanto, debido a message
referencia del message
no se cambia en ninguna parte dentro de su clase interna, el compilador la trata como efectivamente final.
Esto habría arrojado un error:
new Runnable() {
@Override
public void run() {
message = "hey";
System.out.println(message);
}
}.run();
La razón por la cual el compilador java7 arroja un error es debido a un cambio de especificación para lambdas .
Cualquier variable local, parámetro formal o parámetro de excepción usado pero no. Cualquier variable local, parámetro formal o parámetro de excepción usado pero no declarado en una expresión lambda debe ser declarado final o ser efectivamente final (§4.12.4), o una compilación -se produce un error de tiempo donde se intenta el uso.
Clases internas anónimas y lambdas comparten las mismas reglas.
Java 8 (y Lambdas) introducen el término final efectivo : aunque no lo hayas eliminado con la palabra clave final
, si no se modifica, es tan bueno como definitivo.
Cita del tutorial de Oracle: Clases locales :
Sin embargo, a partir de Java SE 8, una clase local puede acceder a las variables y parámetros locales del bloque envolvente que son finales o efectivamente finales . Una variable o parámetro cuyo valor nunca se cambia después de que se inicializa es efectivamente final.
Su mensaje es efectivamente final, por lo que es válido referirse a él desde clases internas anónimas y lambdas.
Si cambia el valor del mensaje, ya no será definitivo :
String message = "Hello world";
new Runnable() {
@Override
public void run() {
System.out.println(message);
}
}.run();
message = "modified";
Y por lo tanto, recibe el siguiente error (de Eclipse):
El mensaje de variable local definido en un ámbito adjunto debe ser final o efectivamente final
O forma javac
:
error: las variables locales a las que se hace referencia desde una clase interna deben ser finales o efectivamente finales
Java 8 hace implícitamente el message
final porque nunca se modifica. Intenta modificarlo en cualquier lugar de tu código y obtendrás un error de compilación (porque esto elimina el final
implícito).
Esto se llama efectivamente final . Cita de la documentación :
Sin embargo, a partir de Java SE 8, una clase local puede acceder a las variables y parámetros locales del bloque envolvente que son finales o efectivamente finales. Una variable o parámetro cuyo valor nunca se cambia después de que se inicializa es efectivamente final.
Sí, en cierto modo es.
Básicamente, se dieron cuenta de que el compilador ya tiene que decidir analizando el código cuando una variable local es "efectivamente final", es decir, su valor nunca se cambia.
Por lo tanto, la semántica no ha cambiado: si bien ya no es necesario declarar explícitamente la variable final
, usted debe asegurarse de que nunca se reasigne.