Contents

Java 8: Expresiones Lambda

Las expresiones lambda son una de las múltiples funcionalidades nuevas que nos ofrece Java 8. Estas expresiones son parte de los primeros pasos de Java hacia la programación funcional, y su cometido es introducirnos a las funciones anónimas mediante las cuales podemos definir el comportamiento de los objetos, y los datos que encapsulan.

¿En qué consiste la programación funcional? La programación funcional es un paradigma de programación basado en las funciones matemáticas, que especifica que una función que recibe un parámetro X, siempre devolverá un resultado Y.
Este paradigma permite definir comportamiento mediante funciones, pudiendo inyectarlo como parámetro de entrada en los objetos, o devolverlo como resultado de otro método.

Introducción a las funciones lambda

Por tanto, deducimos de lo anterior, que las funciones lambda son la funcionalidad que Java ofrece para facilitar la definición de comportamiento mediante parámetros.

Una función lambda consta de los siguientes elementos:

  • Parámetros de entrada
  • Operador lambda
  • Cuerpo del método

/images/lambda_expression.jpg

Ejemplo de expresión lambda

El primer elemento de la expresión lambda, los parámetros de entrada se puede definir como:

  • Expresión lambda sin parámetros de entrada
1
() -> System.out.println("Hello Lambda World!")
  • Expresión lambda con un parámetro de entrada simple
1
x -> x + 10
  • Expresión lambda con múltiples parámetros de entrada
1
(int x, int y) -> { return x + y; } 

Con respecto al cuerpo del método, para los métodos con una única línea de código no es necesario definir las llaves.

1
2
// Expresión lambda con dos parámetros de entrada sin return definido
(String x, String y) -> x.length() - y.length()

Mientras que para métodos con varias líneas, las llaves serán obligatorias.

1
2
3
4
5
// Expresión lambda con varias líneas de código como cuerpo
(String x) -> {     
    //Code...     
    return x.length();
}

Referenciando variables externas

Las expresiones lambda pueden hacer referencia a variables locales finales, o efectivamente finales dentro de la clase donde se definen.

¿Y qué es eso de variables efectivamente finales? Las variables efectivamente finales son variables que, aunque no se definen explícitamente como finales, cumplen los requisitos para poder serlo.

En el siguiente ejemplo podemos ver cómo se utiliza la variable “before” , una variable efectivamente final, dentro de la expresión lambda que filtra los resultados de la lista de ficheros.

1
2
3
4
//Utilizando variables efectivamente finales dentro de funciones lambda
void expire(File root, long before) {  
    root.listFiles(File p -> p.lastModified() <= before);
}

Referencia “this” en las funciones lambda

El uso de “this” en las expresiones lambda hace referencia al objeto en el cual se ha definido la expresión. Siguiendo con el ejemplo anterior, se podría definir una variable final en el objeto que encapsula al método “expire”, y utilizar “this” para hacer referencia a dicha variable.

1
2
3
4
5
6
//Referenciando a 'this' dentro de una función lambda
public final long currentDate = new Date().getTime();

void expire(File root) {  
    root.listFiles(File p -> p.lastModified() <= this.currentDate);
}

Esto es así debido a que las expresiones lambda no son más que una representación de funciones anónimas, y estas no están asociadas a ninguna clase, por tanto, una función lambda no puede referenciarse a sí misma.

Creando nuestra propia expresión lambda con interfaces funcionales

Ahora que ya sabemos cómo funcionan las expresiones lambda, podemos empezar a crear las nuestra. Para ello utilizaremos interfaces funcionales.

Las interfaces funcionales son aquellas que definen un único método abstracto. Las interfaces funcionales también pueden definir a su vez tantos métodos estáticos y métodos default como sean necesarios.

Para crear nuestra interfaz funcional, deberemos utilizar la anotación @FunctionalInterface.

1
2
3
4
@FunctionalInterface
public interface Math{
    int calculate(int x, int y);
}

Una vez creada nuestra interfaz funcional, podremos instanciarla utilizando una expresión lambda, tal y como se define a continuación:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public class Test{

    public static void main(String\[\] args){
        executeMath(5,3,(x,y)->x\*y);
    }

    public int executeMath(int x, int y, Math math){
        return math.calculate(x, y);
    }
}

Si quieres saber más acerca de las interfaces funcionales puedes hacerlo aquí.