Breaking

Post Top Ad

Your Ad Spot

jueves, 19 de diciembre de 2019

Java Lambda Expressions

En este artículo, aprenderá sobre la nueva característica introducida en Java 8, que es soporte para la expresión lambda usando una interfaz funcional.
Las expresiones lambda eran un tema candente cuando se lanzó Java 8. Se agregaron expresiones Lambda en JDK versión 8 para mejorar el rendimiento de Java al aumentar el poder expresivo del lenguaje.
Pero, antes de entrar en lambdas, primero debemos entender qué es una interfaz funcional.

¿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, la Runnableinterfaz del paquete java.langes una interfaz funcional porque constituye solo un método, es decir run().

Ejemplo 1: definir una interfaz funcional en java

  1. import java.lang.FunctionalInterface;
  2. @FunctionalInterface
  3. public interface MyInterface{
  4. double getValue();
  5. }
Nota: La @FunctionalInterfaceanotación no es necesaria, pero es aconsejable usarla porque obliga al compilador de Java a indicar que la interfaz definida es una interfaz funcional y debe tener un solo método abstracto. En Java 7, la interfaz funcional se denominaba Método abstracto único o tipo SAM .
Los SAM se implementaron comúnmente con clases anónimas en Java 7.

Ejemplo 2: Implementar SAM con clases anónimas en java

  1. public class FunctionInterfaceTest {
  2. public static void main(String[] args) {
  3. new Thread(new Runnable() {
  4. @Override
  5. public void run() {
  6. System.out.println("I just implemented the Runnable Functional Interface.");
  7. }
  8. }).start();
  9. }
  10. }
La capacidad de pasar una clase anónima a un constructor o método facilitó la escritura de código Java 7 con menos archivos. Sin embargo, la sintaxis seguía siendo difícil y se requerían muchas líneas de código adicionales.
Java 8 extendió el poder 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 la expresión 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 cambio, se usa para implementar un método definido por una interfaz funcional.

¿Cómo definir la expresión lambda en Java?

La expresión lambda introduce un nuevo elemento de sintaxis y un operador en lenguaje Java. El nuevo operador se denomina operador lambda o operador de flecha (->).
Escribamos un método simple que solo devuelve un valor doble constante.
double getPiValue () {return 3.1415; }
La expresión lambda equivalente para el método anterior es:
() -> 3.1415
En la expresión lambda, el lado izquierdo de la expresión especifica los parámetros requeridos por la expresión, donde como el lado derecho es el cuerpo lambda, que especifica la acción de la expresión lambda.
El cuerpo lambda es de dos tipos.
  1. Un cuerpo con una sola expresión.
    () -> System.out.println ("Las Lambdas son geniales");
  2. Un cuerpo que consiste en un bloque de código.
    () -> {
        doble pi = 3.1415;
        volver pi;
    }
Una expresión lambda también puede tener parámetros. Por ejemplo:
(n) -> (n% 2) == 0
Esta expresión lambda evalúa si el valor de n es par o impar.
Si el cuerpo lambda es un bloque de código, siempre debe devolver un valor explícitamente. Pero, si el cuerpo lambda es solo una expresión, no se requiere la declaración de retorno.
Escribamos un código Java práctico con expresión lambda que simplemente devuelva el valor de Pi.
Como se mencionó anteriormente, la 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.

Ejemplo 3: definir expresión lambda con interfaz funcional en java

Entonces, primero definamos una interfaz funcional MyInterface.java:
  1. import java.lang.FunctionalInterface;
  2. // This is functional interface
  3. @FunctionalInterface
  4. public interface MyInterface{
  5. double getPiValue();
  6. }
Ahora, asignamos la expresión lambda a la instancia de la interfaz funcional.
  1. public class LambdaMain {
  2. public static void main( String[] args ) {
  3. MyInterface myInterface;
  4. myInterface = () -> 3.1415;
  5. System.out.println("Value of Pi = " + myInterface.getPiValue());
  6. }
  7. }
Cuando ejecutas el programa, la salida será:
Valor de Pi = 3.1415
La expresión lambda debe ser compatible con el método abstracto. Esto significa que si asigna () -> "3.1415" a la myInterfaceinstancia, el código es ilegal y no funcionará porque el tipo de Cadena no es compatible con el doble como se define en la interfaz funcional.
Probablemente no usaría una expresión lambda como esta en un programa real. Veamos algún otro ejemplo de expresión lambda que tome en parámetro.

Ejemplo 4: uso de la expresión lambda con parámetros en java

  1. @FunctionalInterface
  2. interface MyInterface {
  3. String reverse(String n);
  4. }
  5. public class ParamLambdaMain {
  6. public static void main( String[] args ) {
  7. MyInterface myInterface = (str) -> {
  8. String result = "";
  9. for (int i = str.length()-1; i >= 0 ; i--)
  10. result += str.charAt(i);
  11. return result;
  12. };
  13. System.out.println("Lambda reversed = " + myInterface.reverse("Lambda"));
  14. }
  15. }
Cuando ejecutas el programa, la salida será:
Lambda invertida = adbmaL

Interfaz funcional genérica

La interfaz funcional anterior solo acepta String y devuelve el objeto String. Sin embargo, podemos hacer que la interfaz funcional sea genérica, de modo que se acepte cualquier tipo de datos.

Ejemplo 5: ¿Cómo puede la interfaz funcional aceptar cualquier tipo de datos en java?

Veamos cómo se hace:
  1. // GenericInterface.java
  2. @FunctionalInterface
  3. interface GenericInterface<T> {
  4. T func(T t);
  5. }
Ahora, esto GenericInterfacees compatible con cualquier expresión lambda que tome un parámetro y devuelva el valor del mismo tipo.
  1. // GenericLambda.java
  2. public class GenericLambda {
  3. public static void main( String[] args ) {
  4. GenericInterface<String> reverse = (str) -> {
  5. String result = "";
  6. for (int i = str.length()-1; i >= 0 ; i--)
  7. result += str.charAt(i);
  8. return result;
  9. };
  10. System.out.println("Lambda reversed = " + reverse.func("Lambda"));
  11. GenericInterface<Integer> factorial = (n) -> {
  12. int result = 1;
  13. for (int i = 1; i <= n; i++)
  14. result = i * result;
  15. return result;
  16. };
  17. System.out.println("factorial of 5 = " + factorial.func(5));
  18. }
  19. }
Cuando ejecutas el programa, la salida será:
Lambda invertida = adbmaL
factorial de 5 = 120

Lambda Expression y Stream API

El nuevo  paquete java.util.stream se ha agregado a JDK8 que permite a los desarrolladores de Java realizar operaciones como buscar, filtrar, asignar, reducir o manipular colecciones como las listas.
Por ejemplo, tenemos una secuencia de datos (en nuestro caso, una Lista de cadenas) 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. Podemos realizar operaciones masivas en la secuencia mediante la combinación de Stream API y expresión Lambda.

Ejemplo 6: Demostración del uso de lambdas con Stream API

  1. import java.util.ArrayList;
  2. import java.util.List;
  3. public class StreamMain {
  4. static List<String> places = new ArrayList<>();
  5. // preparing our data
  6. public static List getPlaces(){
  7. places.add("Nepal, Kathmandu");
  8. places.add("Nepal, Pokhara");
  9. places.add("India, Delhi");
  10. places.add("USA, New York");
  11. places.add("Africa, Nigeria");
  12. return places;
  13. }
  14. public static void main( String[] args ) {
  15. List<String> myPlaces = getPlaces();
  16. System.out.println("Places from Nepal:");
  17. // Filter places from Nepal
  18. myPlaces.stream()
  19. .filter((p) -> p.startsWith("Nepal"))
  20. .map((p) -> p.toUpperCase())
  21. .sorted()
  22. .forEach((p) -> System.out.println(p));
  23. }
  24. }
Cuando ejecutas el programa, la salida será:
Lugares de Nepal:
NEPAL, KATMANDU
NEPAL, POKHARA
La API de flujo nos da acceso a métodos como filter()map()forEach()eso puede tomar una expresión lambda como entrada. Podemos usar los dos métodos incorporados de Java y también definir nuestras propias expresiones basadas en la sintaxis que aprendimos anteriormente. Esto nos permite reducir drásticamente las líneas de código como vimos en el ejemplo anterior.

No hay comentarios.:

Publicar un comentario

Dejanos tu comentario para seguir mejorando!

Post Top Ad

Your Ad Spot

Páginas