English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Tutoriales básicos de Java

Control de flujo Java

Java Arreglo

Java Programación Orientada a Objetos (I)

Java Programación Orientada a Objetos (II)

Java Programación Orientada a Objetos (III)

Manejo de excepciones en Java

Java Lista (List)

Java Cola (Queue)

Java Colección de Mapa

Java Conjunto (Set)

Java Entrada/Salida (I/O)

Java Reader/Writer

Otras temáticas de Java

Java Lambda 表达式

En este artículo, entenderemos las expresiones lambda de Java a través de ejemplos, así como el uso de las interfaces de función, las interfaces de función genérica y el API de flujo.

La expresión lambda es en Java 8Se introdujo por primera vez. Su principal objetivo es mejorar la capacidad de expresión del lenguaje.

Pero, antes de aprender lambda, primero necesitamos entender la interfaz funcional.

¿Qué es una interfaz funcional?

Si el interfaz de Java contiene solo un método abstracto, se lo llama interfaz funcional. Solo este método especifica el uso esperado del interfaz.

por ejemplo, el interfaz Runnable en el paquete java.lang; es una interfaz funcional porque solo consta de un método, es decir, run().

Ejemplo1:Definición de interfaz funcional en java

import java.lang.FunctionalInterface;
@FunctionalInterface
public interface MyInterface{
    //Método abstracto único
    double getValue();
}

En el ejemplo anterior, la interfaz MyInterface tiene un solo método abstracto getValue(). Por lo tanto, es una interfaz funcional.

Aquí, hemos utilizado la anotación @FunctionalInterface. Esta anotación obliga al compilador de Java a indicar que la interfaz es una interfaz funcional. Por lo tanto, no se permite tener más de un método abstracto. Sin embargo, no es obligatorio.

en Java 7en el que las interfaces funcionales se consideranMétodo abstracto único (SAM)tipo. 7en las que el tipo SAM se implementa generalmente mediante clases anónimas.

Ejemplo2:Implementación de SAM utilizando clases anónimas en Java

public class FunctionInterfaceTest {
    public static void main(String[] args) {
        //clase anónima
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Acabo de implementar la interfaz funcional Runnable.");
            }
        }).start();
    }
}

Salida

acabo de implementar la interfaz funcional Runnable.

Aquí, podemos pasar una clase anónima a un método. Esto ayuda a usar Java 7escribir programas con menos código. Sin embargo, la sintaxis sigue siendo difícil y requiere una gran cantidad de líneas de código adicionales.

Java 8Se extiende la funcionalidad de SAM. Dado que sabemos que una interfaz funcional tiene un solo método, no es necesario definir el nombre del método al pasarlo como parámetro. Las expresiones lambda nos permiten hacer esto.

Introducción a las expresiones lambda

Una expresión lambda es esencialmente un método anónimo o sin nombre. La expresión lambda no se puede ejecutar por sí sola. En su lugar, se utiliza para implementar métodos definidos en una interfaz funcional.

¿Cómo se define una expresión lambda en Java?

así es como definimos expresiones lambda en Java.

(lista de parámetros) -> cuerpo de lambda

usando el nuevo operador (->)se conoce como operador de flecha o operador lambda. Exploremos algunos ejemplos,

supongamos que tenemos un método así:

double getPiValue() {
    devolver 3.1415;
}

Podemos escribir este método utilizando una expresión lambda, como se muestra a continuación:}}

(); -> 3.1415

En este caso, el método no tiene parámetros. Por lo tanto, el lado izquierdo del operador incluye un parámetro vacío. El lado derecho es el cuerpo de lambda, que especifica la operación de la expresión lambda. En este caso, regresará un valor3.1415。

Tipos de cuerpo de lambda

En Java, los cuerpos de lambda tienen dos tipos.

1.Cuerpo de expresión individual

(); -> System.out.println("Lambdas son geniales");

Este tipo de cuerpo de lambda se llama cuerpo de expresión.

2.Cuerpo compuesto por bloques de código.

(); -> {
    double pi = 3.1415;
    return pi;
};

Este tipo de cuerpo de lambda se llama cuerpo de bloque. El cuerpo de bloque permite que el cuerpo de lambda contenga múltiples instrucciones. Estas instrucciones se contienen entre paréntesis, y debe agregar un punto y coma después de los paréntesis.

Nota:Para el cuerpo del bloque, siempre debe haber una instrucción return. Sin embargo, un cuerpo de expresión individual no necesita una instrucción return.

Ejemplo3:Expresiones lambda

Vamos a escribir un programa Java que utilice expresiones lambda para devolver el valor de Pi.

Como se mencionó anteriormente, las expresiones lambda no se ejecutan por sí solas. Por el contrario, forman la implementación de métodos abstractos definidos por interfaces funcionales.

Por lo tanto, necesitamos definir primero una interfaz funcional.

import java.lang.FunctionalInterface;
//Esto es una interfaz funcional
@FunctionalInterface
interface MyInterface{
    // 抽象方法
    double getPiValue();
}
public class Main {
    public static void main(String[] args) {
    //声明对MyInterface的引用
    MyInterface ref;
    
    // expresión lambda
    ref = () -> 3.1415;
    
    System.out.println("Pi = "); + ref.getPiValue());
    } 
}

Salida

Pi = 3.1415

En el ejemplo anterior,

  • Hemos creado una interfaz funcional llamada MyInterface. Contiene un método abstracto llamado getPiValue().

  • Dentro de la clase Main, declaramos una referencia a MyInterface. Tenga en cuenta que podemos declarar una referencia a una interfaz, pero no instanciarla. Eso es porque,
     

    //Eso lanzará un error
    MyInterface ref = new myInterface();
    // Esto es válido
    MyInterface ref;
  • Luego, asignamos una expresión lambda a la referencia.

    ref = () -> 3.1415;
  • Finalmente, utilizamos el método getPiValue() del interfaz reference.

    System.out.println("Pi = "); + ref.getPiValue());

Expresiones lambda con parámetros

Hasta ahora, hemos creado expresiones lambda sin parámetros. Sin embargo, al igual que los métodos, las expresiones lambda también pueden tener parámetros. Por ejemplo,

(n) -> (n%2)=0

在此,括号内的变量n是传递给lambda表达式的参数。Lambda主体接受参数并检查其是偶数还是奇数。

Ejemplo4:将lambda表达式与参数一起使用

@FunctionalInterface
interface MyInterface {
    //抽象方法
    String reverse(String n);
}
public class Main {
    public static void main(String[] args) {
                //声明对MyInterface的引用
                //将lambda表达式分配给引用
        MyInterface ref = (str) -> {
            String result = "";
            for (int i = str.length();-1; i >= 0 ; i--){
                result += str.charAt(i);
            }
            
            return result;
        };
        //调用接口的方法
        System.out.println("Lambda reversed = "); + ref.reverse("Lambda"));
    }
}

Salida

Lambda reversed = adbmaL

泛型功能接口

到目前为止,我们已经使用了仅接受一种类型的值的功能接口。例如,

@FunctionalInterface
interface MyInterface {
    String reverseString(String n);
}

上面的功能接口仅接受String并返回String。但是,我们可以使功能接口通用,以便接受任何数据类型。如果不熟悉泛型,请访问Java泛型

Ejemplo5:泛型功能接口和Lambda表达式

// GenericInterface.java
@FunctionalInterface
interface GenericInterface<T> {
    // 泛型方法
    T func(T t);
}
// GenericLambda.java
public class Main {
    public static void main(String[] args) {
                //声明对GenericInterface的引用
                // GenericInterface对String数据进行操作
                //为其分配一个lambda表达式
        GenericInterface<String> reverse = (str) -> {
            String result = "";
            for (int i = str.length();-1; i >= 0 ; i--)
            result += str.charAt(i);
            return result;
        };
        System.out.println("Lambda reversed = "); + reverse.func("Lambda"));
                //声明对GenericInterface的另一个引用
                // GenericInterface对整数数据进行操作
                //为其分配一个lambda表达式
        GenericInterface<Integer> factorial = (n) -> {
            int result = 1;
            for (int i = 1; i <= n; i++)
            result = i * result;
            return result;
        };
        System.out.println("5factorial = " + factorial.func(5));
    }
}

Salida

Lambda reversed = adbmaL
5factorial = 120

En el ejemplo anterior, creamos una interfaz funcional genérica llamada GenericInterface. Contiene un método genérico llamado func().

Dentro de la clase:

  • GenericInterface<String> reverse - Crear una referencia a esta interfaz. Ahora, la interfaz puede manejar datos de tipo String.

  • GenericInterface<Integer> factorial -Crear una referencia a esta interfaz. En este caso, la interfaz opera con datos de tipo Integer.

Expresiones lambda y API de Stream

nuevojava.util.streamEl paquete se ha añadido a JDK8Permite a los desarrolladores de Java ejecutar operaciones de búsqueda, filtrado, mapeo, reducción, entre otros, o operar en listas y otros conjuntos.

Por ejemplo, tenemos un flujo de datos (en nuestro ejemplo una lista de cadenas de caracteres), donde cada cadena de caracteres es el nombre del país y/Combinación de regiones. Ahora podemos procesar este flujo de datos y solo recuperar ubicaciones de Nepal.

Para esto, podemos combinar el uso de API de Stream y expresiones lambda para realizar operaciones en lote en el flujo.

Ejemplo6:Demostrar el uso conjunto de lambda y API de Stream

import java.util.ArrayList;
import java.util.List;
public class StreamMain {
    //Crear un objeto de lista utilizando ArrayList
    static List<String> places = new ArrayList<>();
    //Preparar nuestros datos
    public static List getPlaces(){
        //Añadir lugares y países a la lista
        places.add("Nepal, Kathmandu");
        places.add("Nepal, Pokhara");
        places.add("India, Delhi");
        places.add("USA, New York");
        places.add("Africa, Nigeria");
        return places;
    }
    public static void main(String[] args) {
        List<String> myPlaces = getPlaces();
        System.out.println("Lugares de Nepal:");
        
        myPlaces.stream()
                .filter((p -> p.startsWith("Nepal"))
                .map((p -> p.toUpperCase())
                .sorted()
                .forEach((p -> System.out.println(p));
    }
}

Salida

Lugares de Nepal:
NEPAL, KATHMANDU
NEPAL, POKHARA

En el ejemplo anterior, preste atención a las siguientes declaraciones:

myPlaces.stream()
        .filter((p -> p.startsWith("Nepal"))
        .map((p -> p.toUpperCase())
        .sorted()
        .forEach((p -> System.out.println(p));

Aquí, usamos métodos como filter(), map() y forEach() de la API Stream. Estos métodos pueden tomar una expresión lambda como entrada.

Podemos definir nuestras propias expresiones basándonos en la gramática que hemos aprendido anteriormente. Como se muestra en el ejemplo anterior, esto nos permite reducir significativamente el número de líneas de código.