Expresiones Lambda en Java

Java 8 新特性Nuevas características de Java 8


Una expresión Lambda, también llamada clausura, es la característica nueva más importante que impulsó el lanzamiento de Java 8.

Lambda permite usar una función como parámetro de un método (pasar una función como argumento a un método).

El uso de expresiones Lambda puede hacer que el código sea más conciso y compacto.

Sintaxis

El formato de sintaxis de una expresión lambda es el siguiente:

(parameters) -> expressiono(parameters) ->{ statements; }

parameterses la lista de parámetros,expressiono{ statements; }es el cuerpo de la expresión Lambda. Si solo hay un parámetro, se pueden omitir los paréntesis; si no hay parámetros, también se necesitan paréntesis vacíos.

A continuación se muestra un ejemplo sencillo que demuestra el uso de una expresión Lambda para calcular la suma de dos números:

Ejemplo

// Usando una expresión Lambda para calcular la suma de dos números
MathOperation addition = (a, b) -> a + b;

// Llamando a la expresión Lambda
int result = addition.operation(5, 3);
System.out.println("5 + 3 = " + result);

En el ejemplo anterior, MathOperation es una interfaz funcional que contiene un método abstracto operation. La expresión Lambda(a, b) -> a + bimplementa ese método abstracto, representando la operación de sumar dos parámetros.

Las expresiones Lambda se pueden usar en diversos escenarios, incluyendo operaciones de colecciones, manejo de eventos, etc. A continuación se muestra un ejemplo de recorrido de una lista usando una expresión Lambda:

Ejemplo

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

// Usando una expresión Lambda para recorrer una lista
names.forEach(name -> System.out.println(name));

Las expresiones Lambda introdujeron en Java un estilo más funcional de programación, haciendo el código más conciso y legible. Son una mejora importante de Java 8 hacia la programación funcional.


Características importantes

Concisión

Las expresiones Lambda proporcionan una sintaxis más concisa, especialmente adecuada para interfaces funcionales. En comparación con las clases internas anónimas tradicionales, las expresiones Lambda hacen que el código sea más compacto y reducen la escritura de código repetitivo.

Ejemplo

// Clase interna anónima tradicional
Runnable runnable1 = new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello World!");
    }
};

// Usando una expresión Lambda
Runnable runnable2 = () -> System.out.println("Hello World!");

Soporte de programación funcional

Las expresiones Lambda son una manifestación de la programación funcional; permiten pasar funciones como parámetros a métodos o devolver funciones como valores de retorno. Este soporte hace que Java sea más flexible en programación funcional y pueda manejar mejor tareas como operaciones de colecciones y cálculo paralelo.

Ejemplo

// Usando una expresión Lambda como parámetro pasado a un método
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.forEach(name -> System.out.println(name));

Captura de variables

Las expresiones Lambda pueden acceder a variables del ámbito externo; esta característica se llama captura de variables. Las expresiones Lambda pueden capturar implícitamente variables locales finales o efectivamente finales.

Ejemplo

// Captura de variables
int x = 10;
MyFunction myFunction = y -> System.out.println(x + y);
myFunction.doSomething(5); // Imprime 15

Referencias a métodos

Las expresiones Lambda se pueden simplificar aún más mediante referencias a métodos. Las referencias a métodos le permiten referirse directamente a métodos de clases u objetos existentes, sin escribir código redundante.

Ejemplo

// Usando una referencia a método
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.forEach(System.out::println);

Paralelismo

Las expresiones Lambda permiten implementar operaciones paralelas de forma más conveniente. Al combinar la API Stream con expresiones Lambda, es más fácil realizar cálculos paralelos y mejorar el rendimiento del programa.

Ejemplo

// Usando expresiones Lambda y la API Stream para cálculo paralelo
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.parallelStream().mapToInt(Integer::intValue).sum();

La introducción de las expresiones Lambda hace que la programación en Java sea más flexible y concisa, e impulsa el desarrollo de la programación funcional.


Ejemplos de expresiones Lambda

Ejemplos sencillos de expresiones Lambda:

// 1. 不需要参数,返回值为 5  
() -> 5  
  
// 2. 接收一个参数(数字类型),返回其2倍的值  
x -> 2 * x  
  
// 3. 接受2个参数(数字),并返回他们的差值  
(x, y) -> x – y  
  
// 4. 接收2个int型整数,返回他们的和  
(int x, int y) -> x + y  
  
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)  
(String s) -> System.out.print(s)

Ingrese el siguiente código en el archivo Java8Tester.java:

Archivo Java8Tester.java

public class Java8Tester { public static void main(String args[]){ Java8Tester tester = new Java8Tester(); //Declaración de tipo MathOperation addition = (int a, int b) -> a + b; //Sin declaración de tipo MathOperation subtraction = (a, b) -> a - b; //Declaración de retorno entre llaves MathOperation multiplication = (int a, int b) -> { return a * b; }; //Sin llaves y sin declaración de retorno MathOperation division = (int a, int b) -> a / b; System.out.println("10 + 5 = " + tester.operate(10, 5, addition)); System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction)); System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication)); System.out.println("10 / 5 = " + tester.operate(10, 5, division)); //Sin paréntesis GreetingService greetService1 = message -> System.out.println("Hello " + message); //Con paréntesis GreetingService greetService2 = (message) -> System.out.println("Hello " + message); greetService1.sayMessage("Ejemplo"); greetService2.sayMessage("Google"); } interface MathOperation { int operation(int a, int b); } interface GreetingService { void sayMessage(String message); } private int operate(int a, int b, MathOperation mathOperation){ return mathOperation.operation(a, b); } }

Al ejecutar el script anterior, el resultado es:

$ javac Java8Tester.java 
$ java Java8Tester
10 + 5 = 15
10 - 5 = 5
10 x 5 = 50
10 / 5 = 2
Hello Ejemplo
Hello Google

Al usar expresiones Lambda, se deben tener en cuenta los siguientes dos puntos:

  • Las expresiones Lambda se utilizan principalmente para definir interfaces de tipo método que se ejecutan en línea (por ejemplo, una interfaz de método simple). En el ejemplo anterior, usamos varios tipos de expresiones Lambda para definir el método de la interfaz MathOperation, y luego definimos la ejecución de operation.

  • Las expresiones Lambda eliminan la molestia de usar métodos anónimos y otorgan a Java una capacidad de programación funcional simple pero potente.


Ámbito de variables

Las expresiones lambda solo pueden hacer referencia a variables locales externas marcadas como final; esto significa que no se pueden modificar las variables locales definidas fuera del ámbito dentro de la lambda; de lo contrario, se producirá un error de compilación.

Ingrese el siguiente código en el archivo Java8Tester.java:

Archivo Java8Tester.java

public class Java8Tester { final static String salutation = "Hello! "; public static void main(String args[]){ GreetingService greetService1 = message -> System.out.println(salutation + message); greetService1.sayMessage("Ejemplo"); } interface GreetingService { void sayMessage(String message); } }

Al ejecutar el script anterior, el resultado es:

$ javac Java8Tester.java 
$ java Java8Tester
Hello! Ejemplo

También podemos acceder directamente a variables locales externas dentro de una expresión lambda:

Archivo Java8Tester.java

public class Java8Tester { public static void main(String args[]) { final int num = 1; Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num)); s.convert(2); //El resultado es 3 } public interface Converter<T1, T2> { void convert(int i); } }

Las variables locales de una expresión lambda no necesitan declararse como final, pero no deben ser modificadas por código posterior (es decir, tienen implícitamente la semántica de final).

int num = 1;  
Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num));
s.convert(2);
num = 5;  
//报错信息:Local variable num defined in an enclosing scope must be final or effectively 
 final

Dentro de una expresión Lambda no se permite declarar un parámetro o variable local con el mismo nombre que una variable local.

String first = "";  
Comparator<String> comparator = (first, second) -> Integer.compare(first.length(), second.length());  //编译会出错 

Java 8 新特性Nuevas características de Java 8

Otras extensiones