una son que privada otra objeto nombre llevan las internas interna interfaz externa dentro crear clases clase java lambda anonymous-inner-class

java - son - que es una interfaz interna



Las lambdas de Java tienen diferentes requisitos variables que las clases internas anónimas (2)

Esto no compilará

public class Example { private final int x; private final int y = 2 * x; public Example() { x = 10; } }

pero esto:

public class Example { private final int x; private final int y; public Example() { x = 10; y = 2 * x; } }

y también esto:

public class Example { private final int x = 10; private final int y = 2 * x; }

Entonces no tiene nada que ver con lambdas. Un campo que se inicializa en la misma línea en la que se declara se evalúa antes de que se ejecute el constructor. Entonces, en ese punto, la variable ''val'' (o en este ejemplo ''x'') no se ha inicializado.

Tengo una clase interna anónima y una lambda equivalente. ¿Por qué las reglas de inicialización de variables son más estrictas para el lambda, y hay una solución más limpia que una clase interna anónima o inicializándola en el constructor?

import java.util.concurrent.Callable; public class Immutable { private final int val; public Immutable(int val) { this.val = val; } // Works fine private final Callable<String> anonInnerGetValString = new Callable<String>() { @Override public String call() throws Exception { return String.valueOf(val); } }; // Doesn''t compile; "Variable ''val'' might not have been initialized" private final Callable<String> lambdaGetValString = () -> String.valueOf(val); }

Editar: me encontré con una solución: usar un getter para val .


El capítulo sobre estados de cuerpos de expresión lambda

A diferencia del código que aparece en las declaraciones de clase anónimas, el significado de los nombres y las palabras clave this y super aparecen en un cuerpo lambda, junto con la accesibilidad de las declaraciones referenciadas, son las mismas que en el contexto circundante (excepto que los parámetros lambda introducen nombres nuevos).

La transparencia de this (tanto explícita como implícita) en el cuerpo de una expresión lambda, es decir, tratarla igual que en el contexto circundante, permite una mayor flexibilidad para las implementaciones y evita que el significado de los nombres no calificados en el cuerpo sea dependiente. en la resolución de sobrecarga.

Son más estrictos por eso.

El contexto circundante, en este caso, es una asignación a un campo y el problema es un acceso de un campo, val , un campo final blanco, en el lado derecho de la expresión.

Los estados de especificación de lenguaje Java

Cada variable local (§14.4) y cada campo final blanco (§4.12.4, §8.3.1.2) deben tener un valor definitivamente asignado cuando se produce cualquier acceso de su valor.

Un acceso a su valor consiste en el nombre simple de la variable (o, para un campo, el nombre simple del campo calificado por this ) que aparece en cualquier parte de una expresión, excepto como el operando de la izquierda del operador de asignación simple = (§ 15.26.1).

Para cada acceso de una variable local o campo final blanco x , x debe asignarse definitivamente antes del acceso, o se produce un error en tiempo de compilación.

Luego continúa diciendo

Deje que C sea ​​una clase, y sea V un campo de miembro no static final blanco de C , declarado en C Entonces:

  • V definitivamente no está asignado (y, además, no está definitivamente asignado) antes del inicializador de instancias más a la izquierda (§8.6) o del inicializador de variables de instancia de C

  • V es [un] asignado antes de que un inicializador de instancia o un inicializador de variable de instancia de C distinto del iff más a la izquierda V sea ​​[un] asignado después del inicializador de instancia precedente o el inicializador de variable de instancia de C

Tu código básicamente se ve así

private final int val; // leftmost instance variable initializer, val still unassigned private final Callable<String> anonInnerGetValString = ... // still unassigned after preceding variable initializer private final Callable<String> lambdaGetValString = ...

Por lo tanto, el compilador determina que val sin asignar cuando se trata de acceder dentro de la expresión de inicialización para lambdaGetValString .

Las reglas anteriores se aplican al uso de un nombre simple, val , no a una expresión calificada, this.val . Puedes usar

final Callable<String> lambdaGetValString = () -> String.valueOf(this.val);