Java: captura de variables de expresión Lambda con ejemplos

Las variables definidas por el ámbito adjunto de una expresión lambda son accesibles dentro de la expresión lambda. Por ejemplo, una expresión lambda puede usar una instancia o una variable estática definida por su clase adjunta. Una expresión lambda también tiene acceso (tanto explícita como implícitamente), que se refiere a la instancia de invocación de la clase envolvente de la expresión lambda. Por lo tanto, una expresión lambda puede obtener o establecer el valor de una variable intrínseca o estática y llamar a un método definido por su clase envolvente.

 Expresión lambda en java El uso de una variable local es como se indica.

Sin embargo, cuando una expresión lambda usa una variable local de su ámbito envolvente, se crea una situación especial que se denomina captura de variable. En este caso, una expresión lambda solo puede usar variables locales que sean efectivamente finales . Una variable efectivamente final es aquella cuyo 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.

Es importante comprender que una variable local del ámbito adjunto no puede ser modificada por la expresión lambda. Hacerlo eliminaría su estado final efectivo, lo que lo haría ilegal para su captura.

Hay ciertos puntos clave a tener en cuenta, que son los siguientes: 

  1. Cualquier variable local, parámetro formal o parámetro de excepción que se use pero no se declare en una expresión lambda debe declararse final o ser efectivamente final, o se producirá un error en tiempo de compilación cuando se intente usar.
  2. Cualquier variable local utilizada pero no declarada en un cuerpo lambda debe asignarse definitivamente antes del cuerpo lambda, o se producirá un error en tiempo de compilación.
  3. Se aplican reglas similares sobre el uso de variables en el cuerpo de una clase interna. La restricción a variables finales efectivas prohíbe el acceso a variables locales que cambian dinámicamente, cuya captura probablemente introduciría problemas de concurrencia. En comparación con la restricción final, reduce la carga administrativa de los programadores.
  4. La restricción a las variables finales efectivas incluye variables de bucle estándar, pero no variables de bucle mejoradas, que se tratan como distintas para cada iteración del bucle.

El siguiente programa ilustra la diferencia entre variables locales efectivamente finales y mutables:

Ejemplo 1

Java

// Java Program Illustrating Difference between
// Effectively final and Mutable Local Variables
  
// Importing reqiored classes
import java.io.*;
// An example of capturing a local variable from the
// enclosing scope
  
// Inrterface
interface MyFunction {
  
    // Method inside the interface
    int func(int n);
}
  
// Main class
class GFG {
  
    // Main driver method
    public static void main(String[] args)
    {
  
        // Custom local variable that can be captured
        int number = 10;
  
        MyFunction myLambda = (n) ->
        {
  
            // This use of number is OK It does not modify
            // num
            int value = number + n;
  
            // However, the following is illegal because it
            // attempts to modify the value of number
  
            // number++;
            return value;
        };
  
        // The following line would also cause an error,
        // because it would remove the effectively final
        // status from num. number = 9;
  
        System.out.println("GFG!");
    }
}
Producción

GFG!

Explicación de salida: 

Como indican los comentarios, el número es efectivamente definitivo y, por lo tanto, puede usarse dentro de myLambda. Sin embargo, si se modificara el número, ya sea dentro o fuera de la lambda, el número perdería su estado final efectivo. Esto provocaría un error y el programa no se compilaría. 

Ejemplo 2

Java

// Java Program Illustrating Difference between
// Effectively final and Mutable Local Variables
  
// Importing input output classes
import java.io.*;
  
// Interface
interface MyInterface {
  
    // Method inside the interface
    void myFunction();
}
  
// Main class
class GFG {
  
    // Custom initialization
    int data = 170;
  
    // Main driver method
    public static void main(String[] args)
    {
  
        // Creating object of this class
        // inside the main() method
        GFG gfg = new GFG();
  
        // Creating object of interface
        // inside the main() method
        MyInterface intFace = () ->
        {
            System.out.println("Data : " + gfg.data);
            gfg.data += 500;
  
            System.out.println("Data : " + gfg.data);
        };
  
        intFace.myFunction();
        gfg.data += 200;
  
        System.out.println("Data : " + gfg.data);
    }
}
Producción

Data : 170
Data : 670
Data : 870

Nota: es importante enfatizar que una expresión lambda puede usar y modificar una variable de instancia de su clase de invocación. Simplemente no puede usar una variable local de su alcance adjunto a menos que esa variable sea efectivamente definitiva.

Publicación traducida automáticamente

Artículo escrito por abhi0709singh y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *