Expresiones Java Lambda
Expresiones Java Lambda
En este artículo, aprenderemos sobre la expresión lambda de Java y el uso de la expresión lambda con interfaces funcionales, interfaz funcional genérica y API de transmisión con la ayuda de ejemplos.
La expresión lambda se introdujo por primera vez en Java 8. Su objetivo principal es aumentar el poder expresivo del lenguaje.
Pero, antes de entrar en lambdas, primero debemos entender las interfaces funcionales.
¿Qué es la interfaz funcional?
Si una interfaz Java contiene uno y solo un método abstracto, se denomina interfaz funcional. Este único método especifica el propósito previsto de la interfaz.
Por ejemplo, el Runnable
interfaz del paquete java.lang
; es una interfaz funcional porque constituye solo un método, es decir, run()
.
Ejemplo 1:Definir una interfaz funcional en java
import java.lang.FunctionalInterface;
@FunctionalInterface
public interface MyInterface{
// the single abstract method
double getValue();
}
En el ejemplo anterior, la interfaz MyInterface solo tiene un método abstracto getValue(). Por lo tanto, es una interfaz funcional.
Aquí, hemos usado la anotación @FunctionalInterface
. La anotación obliga al compilador de Java a indicar que la interfaz es una interfaz funcional. Por lo tanto, no permite tener más de un método abstracto. Sin embargo, no es obligatorio.
En Java 7, las interfaces funcionales se consideraban como métodos abstractos únicos o SAM escribe. Los SAM se implementaron comúnmente con clases anónimas en Java 7.
Ejemplo 2:Implementar SAM con clases anónimas en java
public class FunctionInterfaceTest {
public static void main(String[] args) {
// anonymous class
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("I just implemented the Runnable Functional Interface.");
}
}).start();
}
}
Salida :
I just implemented the Runnable Functional Interface.
Aquí, podemos pasar una clase anónima a un método. Esto ayuda a escribir programas con menos códigos en Java 7. Sin embargo, la sintaxis seguía siendo difícil y se requerían muchas líneas de código adicionales.
Java 8 amplió la potencia de un SAM yendo un paso más allá. Como sabemos que una interfaz funcional tiene solo un método, no debería haber necesidad de definir el nombre de ese método al pasarlo como argumento. La expresión lambda nos permite hacer exactamente eso.
Introducción a las expresiones lambda
La expresión lambda es, esencialmente, un método anónimo o sin nombre. La expresión lambda no se ejecuta por sí sola. En su lugar, se utiliza para implementar un método definido por una interfaz funcional.
¿Cómo definir la expresión lambda en Java?
Así es como podemos definir la expresión lambda en Java.
(parameter list) -> lambda body
El nuevo operador (->
) utilizado se conoce como operador flecha u operador lambda. Es posible que la sintaxis no esté clara en este momento. Exploremos algunos ejemplos,
Supongamos que tenemos un método como este:
double getPiValue() {
return 3.1415;
}
Podemos escribir este método usando la expresión lambda como:
() -> 3.1415
Aquí, el método no tiene ningún parámetro. Por lo tanto, el lado izquierdo del operador incluye un parámetro vacío. El lado derecho es el cuerpo lambda que especifica la acción de la expresión lambda. En este caso, devuelve el valor 3,1415.
Tipos de cuerpo Lambda
En Java, el cuerpo lambda es de dos tipos.
() -> System.out.println("Lambdas are great");
Este tipo de cuerpo lambda se conoce como cuerpo de expresión.
() -> {
double pi = 3.1415;
return pi;
};
Este tipo de cuerpo lambda se conoce como cuerpo de bloque. El cuerpo del bloque permite que el cuerpo lambda incluya varias declaraciones. Estas declaraciones están encerradas entre llaves y debe agregar un punto y coma después de las llaves.
Nota :Para el cuerpo del bloque, puede tener una declaración de devolución si el cuerpo devuelve un valor. Sin embargo, el cuerpo de la expresión no requiere una declaración de retorno.
Ejemplo 3:Expresión Lambda
Escribamos un programa Java que devuelva el valor de Pi usando la expresión lambda.
Como se mencionó anteriormente, una expresión lambda no se ejecuta por sí sola. Más bien, forma la implementación del método abstracto definido por la interfaz funcional.
Entonces, primero debemos definir una interfaz funcional.
import java.lang.FunctionalInterface;
// this is functional interface
@FunctionalInterface
interface MyInterface{
// abstract method
double getPiValue();
}
public class Main {
public static void main( String[] args ) {
// declare a reference to MyInterface
MyInterface ref;
// lambda expression
ref = () -> 3.1415;
System.out.println("Value of Pi = " + ref.getPiValue());
}
}
Salida :
Value of Pi = 3.1415
En el ejemplo anterior,
- Hemos creado una interfaz funcional llamada MyInterface . Contiene un solo método abstracto llamado
getPiValue()
- Dentro de Principal class, hemos declarado una referencia a MyInterface . Tenga en cuenta que podemos declarar una referencia de una interfaz pero no podemos instanciar una interfaz. Eso es,
// it will throw an error MyInterface ref = new myInterface(); // it is valid MyInterface ref;
- Luego asignamos una expresión lambda a la referencia.
ref = () -> 3.1415;
- Finalmente, llamamos al método
getPiValue()
utilizando la interfaz de referencia. Cuando
System.out.println("Value of Pi = " + ref.getPiValue());
Expresiones Lambda con parámetros
Hasta ahora hemos creado expresiones lambda sin ningún parámetro. Sin embargo, al igual que los métodos, las expresiones lambda también pueden tener parámetros. Por ejemplo,
(n) -> (n%2)==0
Aquí, la variable n dentro del paréntesis es un parámetro pasado a la expresión lambda. El cuerpo lambda toma el parámetro y comprueba si es par o impar.
Ejemplo 4:uso de la expresión lambda con parámetros
@FunctionalInterface
interface MyInterface {
// abstract method
String reverse(String n);
}
public class Main {
public static void main( String[] args ) {
// declare a reference to MyInterface
// assign a lambda expression to the reference
MyInterface ref = (str) -> {
String result = "";
for (int i = str.length()-1; i >= 0 ; i--)
result += str.charAt(i);
return result;
};
// call the method of the interface
System.out.println("Lambda reversed = " + ref.reverse("Lambda"));
}
}
Salida :
Lambda reversed = adbmaL
Interfaz funcional genérica
Hasta ahora hemos utilizado la interfaz funcional que acepta solo un tipo de valor. Por ejemplo,
@FunctionalInterface
interface MyInterface {
String reverseString(String n);
}
La interfaz funcional anterior solo acepta String
y devuelve String
. Sin embargo, podemos hacer que la interfaz funcional sea genérica, de modo que se acepte cualquier tipo de datos. Si no está seguro acerca de los genéricos, visite Java Generics.
Ejemplo 5:interfaz funcional genérica y expresiones lambda
// GenericInterface.java
@FunctionalInterface
interface GenericInterface<T> {
// generic method
T func(T t);
}
// GenericLambda.java
public class Main {
public static void main( String[] args ) {
// declare a reference to GenericInterface
// the GenericInterface operates on String data
// assign a lambda expression to it
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"));
// declare another reference to GenericInterface
// the GenericInterface operates on Integer data
// assign a lambda expression to it
GenericInterface<Integer> factorial = (n) -> {
int result = 1;
for (int i = 1; i <= n; i++)
result = i * result;
return result;
};
System.out.println("factorial of 5 = " + factorial.func(5));
}
}
Salida :
Lambda reversed = adbmaL factorial of 5 = 120
En el ejemplo anterior, hemos creado una interfaz funcional genérica llamada GenericInterface . Contiene un método genérico llamado func()
.
Aquí, dentro de la clase Principal,
GenericInterface<String> reverse
- crea una referencia a la interfaz. La interfaz ahora opera enString
tipo de datos.GenericInterface<Integer> factorial
- crea una referencia a la interfaz. La interfaz, en este caso, opera en elInteger
tipo de datos.
Expresión Lambda y API de transmisión
El nuevo paquete java.util.stream se ha agregado a JDK8, lo que permite a los desarrolladores de Java realizar operaciones como buscar, filtrar, mapear, reducir o manipular colecciones como Lists
.
Por ejemplo, tenemos un flujo de datos (en nuestro caso, un List
de String
) donde cada cadena es una combinación del nombre del país y el lugar del país. Ahora, podemos procesar este flujo de datos y recuperar solo los lugares de Nepal.
Para esto, podemos realizar operaciones masivas en la transmisión mediante la combinación de Stream API y Lambda expression.
Ejemplo 6:Demostración del uso de lambdas con Stream API
import java.util.ArrayList;
import java.util.List;
public class StreamMain {
// create an object of list using ArrayList
static List<String> places = new ArrayList<>();
// preparing our data
public static List getPlaces(){
// add places and country to the list
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("Places from Nepal:");
// Filter places from Nepal
myPlaces.stream()
.filter((p) -> p.startsWith("Nepal"))
.map((p) -> p.toUpperCase())
.sorted()
.forEach((p) -> System.out.println(p));
}
}
Salida :
Places from Nepal: NEPAL, KATHMANDU NEPAL, POKHARA
En el ejemplo anterior, observe la declaración,
myPlaces.stream()
.filter((p) -> p.startsWith("Nepal"))
.map((p) -> p.toUpperCase())
.sorted()
.forEach((p) -> System.out.println(p));
Aquí, estamos usando métodos como filter()
, map()
y forEach()
de la API de transmisión. Estos métodos pueden tomar una expresión lambda como entrada.
También podemos definir nuestras propias expresiones en función de la sintaxis que aprendimos anteriormente. Esto nos permite reducir drásticamente las líneas de código como vimos en el ejemplo anterior.
Java
- interfaz C#
- Operadores Java
- Expresiones, declaraciones y bloques de Java
- Interfaz Java
- Prueba de Java con recursos
- Anotaciones Java
- Interfaz vs clase abstracta en Java:¿cuál es la diferencia?
- Java - Expresiones regulares
- Java - Interfaces
- Java 9 - Métodos de interfaz privada
- Java 8 - Expresiones lambda