viernes, 5 de febrero de 2016

Lambda expresiones Java 8

Hola amigos anterior a la versión 8 de Java se contaba con el soporte para tres paradigmas de programación:


  • Programación Procedural
  • Programación Orientada a Objetos
  • Programación Genérica


En esta versión se añade uno más:


  • Programación Funcional


Todas las características nuevas, tanto a nivel de lenguaje como de librerías, que dan soporte a este nuevo (en el caso de Java) paradigma fueron añadidos a Java como parte del proyecto Lambda.

En este artículo intentaré explicar y definir lo que es la Programación Funcional, aprenderemos a escribir código mucho más rápido, más conciso y con menos errores que cuando usábamos técnicas anteriores.

La programación funcional tiene sus raíces en el cálculo lambda, en el caso específico de Java, este paradigma se apoya en las expresiones lambda, un recurso sintáctico que permite expresar funciones anónimas, que no pertenecen a ninguna clase y que implementan interfaces funcionales (un solo método abstracto) de forma muy compacta.

Los lenguajes de programación funcionales, especialmente los que son puramente funcionales, son aquellos donde las variables que se manejan no tienen estado — no hay cambios en éstas a lo largo del tiempo — y son inmutables — no pueden cambiarse los valores a lo largo de la ejecución, además los programas se estructuran componiendo expresiones que se evalúan como funciones, han sido enfatizados en el ambiente académico principalmente y no tanto en el desarrollo de software comercial, aunque lenguajes como R (estadística), Mathematica (matemáticas simbólicas), Haskell y F# en Microsoft.NET son solamente algunos ejemplos de usos en la industria a través de lenguajes de dominio específico.

La programación funcional también puede ser desarrollada en lenguajes que no fueron diseñados específicamente con este enfoque en mente, como es el caso de Java en su versión 8, donde como ya hemos explicado se ha incorporando la programación funcional y el uso de las expresiones lambda, brindando una oportunidad de desarrollo que hasta el momento el lenguaje no tenía, actualizándolo a los tiempos que vivimos.

Veamos a continuación la sintaxis de una expresión Lambda:

(Parámetros) -> { cuerpo de la expresión }



Su sintaxis es muy sencilla, se comienza con unos paréntesis () donde van los argumentos del método seguidos de -> para indicar el cuerpo que debe ser denotado por corchetes {} a menos que sea una sola línea. Los aspectos a tener en cuenta en cada declaración serían los siguientes:


  1. El operador lambda (->) es mandatorio.
  2. Si la expresión posee una sola línea, pueden omitirse los paréntesis y/o llaves.
  3. Si y solo si se esta enviando un único parámetro es posible quitar los paréntesis.
  4. Si no se envía ningún parámetro se deben de colocar los paréntesis vacíos.


Ejemplo:

(int x) -> x * x
 
(int x, int y) -> { return x + y; }
 
(int value) -> System.out.println("%d", value)
 
String s -> textfield.setText(s.toUpperCase())


La inferencia de tipos nos ayuda a simplificar aun más nuestras expresiones:

x -> x * x
 
x, y -> x + y
 
s -> textfield.setText(s.toUpperCase())


Seguidamente veremos algunos ejemplos de uso:

import java.util.function.*;
 
public class Main {
 
    public static void main(String[] args) {
 
        Consumer imprimir = (texto) -> System.out.println(texto);
 
        imprimir.accept("\nFuck Yehaaa!!!");
 
        Predicate verifyAge = (age) -> age > 10;
 
        System.out.println("\nLa edad es mayor a 10: " + verifyAge.test(12));
 
        BinaryOperator sum = (x, y) -> { return x + y; };
 
        System.out.println("\nLa suma de 23.7 + 65.2 es igual a: " + sum.apply(23.7, 65.2));
 
    } // main
 
} // Main


La salida en pantalla sería:

La edad es mayor a 10: true
 
La suma de 23.7 + 65.2 es igual a: 88.9


En este ejemplo hemos usado varias interfaces funcionales, aquellas incluidas en el paquete java.util.function, en las cuales nos apoyamos para ejemplificar el uso de las expresiones lambda. En la línea 9 hacemos uso de la interfaz funcional Consumer la cual contiene un método abstracto llamado “accept” el cual toma un parámetro T y no devuelve nada. Al igualar la instancia de esta interfaz a la expresión lambda estamos asignando una funcionalidad al método “accept”, estaríamos implementandolo al vuelo, en otras palabras; en este caso imprimimos el objeto String que pasamos como parámetro aunque como podemos observar no lo especificamos en la expresión lambda ya que el compilador infiere o toma esta información al momento de crear nuestra instancia del objeto Consumer donde especificamos de que tipo será el parámetro T. En la línea 11 ejecutamos el método “accept” pasándole un texto cualquiera, acción que se ejecuta de manera satisfactoria generando la primera línea en la salida en pantalla.

Así sucede con las líneas siguientes donde hacemos uso de las interfaces funcionales Predicate y BinaryOperator, a las que asignamos su respectiva expresión lambda obteniendo el resultado esperado como podemos constatar en la salida en pantalla.

No hay comentarios.:

Publicar un comentario