English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
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.
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().
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.
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.
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.
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。
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.
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());
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主体接受参数并检查其是偶数还是奇数。
@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泛型。
// 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.
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.
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.