Diferencia entre final y efectivamente final


Estoy jugando con lambdas en Java 8 y me encontré con warning local variables referenced from a lambda expression must be final or effectively final. Sé que cuando uso variables dentro de la clase anónima deben ser finales en la clase externa, pero aún así - ¿cuál es la diferencia entre final y efectivamente final?

Author: alex, 2014-01-05

11 answers

... a partir de Java SE 8, una clase local puede acceder a variables y parámetros locales del bloque que encierra que son finales o efectivamente finales. Una variable o parámetro cuyo valor nunca se cambia después de inicializarse es efectivamente final.

Por ejemplo, supongamos que la variable numberLength no se declara final, y se agrega la instrucción de asignación marcada en el constructor PhoneNumber:

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 instrucción de asignación, la variable numberLength ya no es definitivo. Como resultado, el compilador Java genera un mensaje de error similar a "las variables locales referenciadas 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

 184
Author: ꜱᴜʀᴇꜱʜ ᴀᴛᴛᴀ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-03 16:13:00

Me parece que la forma más sencilla de explicar "efectivamente final" es imaginar la adición del modificador final 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.

 110
Author: Maurice Naftalin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-03 15:33:48

Según los documentos :

Una variable o parámetro cuyo valor nunca se cambia después de inicializarse 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;
    }
}
 30
Author: Mark Elliot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-11 22:39:53

De un artículo de 'Brian Goetz',

'Effectively final' es una variable que no daría error al compilador si se añadiera "final"

Lambda-state-final-Brian Goetz

 23
Author: Ajeet Ganga,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-15 23:14:40

Esta variable de abajo es final, por lo que no podemos cambiar su valor una vez inicializado. 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 por defecto. Pero la existencia de la segunda línea en el código hace que no sea final. Así que si eliminamos la 2ª línea del código anterior, nuestra variable es ahora " efectivamente final " ...

int variable = 123;

So.. Cualquier variable que se asigne una y solo una vez, es "efectivamente final".

 12
Author: Eurig Jones,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-03 23:38:19

Una variable es final o efectivamente final cuando se inicializa una vez y nunca mutado en propietario de su clase. Y nosotros no se puede inicializar en bucles o las clases internas.

Final:

final int number;
number = 23;

Efectivamente Final :

int number;
number = 34;
 6
Author: samadadi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-07 16:01:27

Cuando una expresión lambda usa una variable local asignada desde su espacio de encierro hay una restricción importante. Una expresión lambda solo puede usar una variable local cuyo valor no cambie. Esa restricción se conoce como" captura variable " que se describe como; valores de captura de expresión lambda, no variables.
Las variables locales que una expresión lambda puede usar se conocen como"efectivamente final".
Una variable efectivamente final es aquella cuya el valor no cambia después de que se asigna por primera vez. No hay necesidad de declarar explícitamente tal variable como final, aunque hacerlo no sería un error.
Veamos con un ejemplo, tenemos una variable local i que se inicializa con el valor 7, con la expresión lambda que estamos tratando de cambiar ese valor asignando un nuevo valor a i. Esto dará lugar a un error del compilador: " La variable local i definida en un ámbito de inclusión debe ser final o efectivamente final "

@FunctionalInterface
interface IFuncInt {
    int func(int num1, int num2);
    public String toString();
}

public class LambdaVarDemo {

    public static void main(String[] args){             
        int i = 7;
        IFuncInt funcInt = (num1, num2) -> {
            i = num1 + num2;
            return i;
        };
    }   
}
 6
Author: infoj,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-29 15:21:15

El tema final efectivo se describe en JLS 4.12.4 y el último párrafo consiste en una explicación clara:

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 el contrario, una variable o parámetro local que se declara final en un programa válido se convierte efectivamente final si se elimina el modificador final.

 2
Author: Dmitry N.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-25 04:24:52
public class LambdaScopeTest {
    public int x = 0;        
    class FirstLevel {
        public int x = 1;    
        void methodInFirstLevel(int x) {

            // The following statement causes the compiler to generate
            // the error "local variables referenced from a lambda expression
            // must be final or effectively final" in statement A:
            //
            // x = 99; 

        }
    }    
}

Como otros han dicho, una variable o parámetro cuyo valor nunca se cambia después de inicializarse es efectivamente final. En el código anterior, si cambia el valor de x en la clase interna FirstLevel, entonces el compilador le dará el mensaje de error:

Las variables locales a las que se hace referencia desde una expresión lambda deben ser finales o efectivamente finales.

 1
Author: Tenacious,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-26 06:44:59

Si pudiera agregar el modificador final a una variable local, sería efectivamente definitivo.

Las expresiones Lambda pueden acceder a

  • Variables estáticas,

  • Variables de instancia,

  • Efectivamente final parámetros del método, y

  • Efectivamente final variables locales.

Fuente: OCP: Oracle Certified Professional Java SE 8 Programmer II Study Guide, Jeanne Boyarsky, Scott Selikoff

Además,

Una variable effectively final es una variable cuyo valor nunca es cambiado, pero no se declara con la palabra clave final.

Fuente: Comenzando con Java: De Estructuras de Control a través de Objetos (6a Edición), Tony Gaddis

Además, no olvide el significado de final que se inicializa exactamente una vez antes de que se use por primera vez.

 1
Author: snr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-24 06:00:19

Sin embargo, a partir de Java SE 8, una clase local puede acceder a variables y parámetros locales del bloque >enclosing que son finales o efectivamente finales.

Esto no se inició en Java 8, lo uso desde hace mucho tiempo. Este código utilizado (antes de java 8) para ser legal:

String str = ""; //<-- not accesible from anonymous classes implementation
final String strFin = ""; //<-- accesible 
button.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
         String ann = str; // <---- error, must be final (IDE's gives the hint);
         String ann = strFin; // <---- legal;
         String str = "legal statement on java 7,"
                +"Java 8 doesn't allow this, it thinks that I'm trying to use the str declared before the anonymous impl."; 
         //we are forced to use another name than str
    }
);
 -6
Author: FiruzzZ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-30 10:54:05