JDK 8 y el proyecto Lambda

El próximo año Oracle planea liberar la versión 8 del JDK, que entre las novedades incluidas está el proyecto lambda. Dicho proyecto trae un par de características ampliamente usadas en el mundo de la programación funcional: los closures (clausuras) y las funciones anónimas.

En este post repasamos éstos conceptos y mostramos como sería la versión que Oracle esta cocinando, y aunque todavia falta un tiempo para la versión final y pueden haber cambios, las bases ya estan puestas y podemos darnos una idea.

El propósito de las funciones anónimas( también conocidas como expresiones lambda ) es muy simple: crear y usar funciones sin necesidad de asignarles un nombre o identificador, de manera que puedan ser usadas para componer o complementar otras funciones.

Modificado el ejemplo original escrito en java "tradicional", la idea es obtener una lista de discos si tienen canciones "ranqueadas" con mas de 4 puntos.

List<Album> favs = new ArrayList<>();
for (Album a : albums) {
    boolean hasFavorite = false;
    for (Track t : a.tracks) {
        if (t.rating >= 4) {
            hasFavorite = true;
            break;
        }
    }
    if (hasFavorite)
        favs.add(a);
}

Con la nueva version de Java y usando funciones anónimas quedaría de la siguiente manera:

List<Album> favs =
        albums.filter(a -> a.tracks.anyMatch(t -> (t.rating >= 4)))
        .into(new ArrayList<>());

Aquí, el papel de funciones anónimas son tanto "a -> a.tracks.anyMatch( ... )" como "t -> (t.rating >= 4)", y la sintaxis puede interpretarse como:

argumentos -> ( cuerpo de la funcion ).

Las funciones anónimas ayudan mucho cuando se trata de programas que requieren de varias expresiones para obtener un resultado y donde cada expresion puede ser separada en una función. Dado que pueden ser creadas en una misma sentencia, la mayoría de las veces resulta conveniente y facil de leer en vez de escribirlas por separado y hacer un mapa mental de todas las funciones involucradas en un bloque de código.

Otra cosa que podemos resaltar es que en la función anónima "t -> (t.rating >= 4), a "t" no se le tuvo que especificar el tipo de dato, el compilador lo infiere del contexto desde donde se define la función, en este caso el tipo es Track. Es decir, "anyMatch" al ser una función de la lista de tracks, cuando se ejecuta, se pasa como parámetro cada track y se le asigna a "t" por cada vez que se ejecute la función.

Los Closures, por otra parte, son un tema que involucra una funcion y el acceso a variables definidas fuera de su ámbito local. Haciendo un pequeño ajuste al programa anterior, si quisieramos que además de canciones ranqueadas con más de 4 puntos, el disco tenga por lo menos 2 canciones, el programa podría verse asi:

List<Album> favs =
        albums.filter( a -> a.tracks.anyMatch(t -> (t.rating >= 4 && a.size() > 1)) )
        .into(new ArrayList<>());

Ahora nuestra función anónima "t -> (t.rating >= 4 && a.size() > 1)" tiene un nuevo elemento que es "a". En el contexto o ámbito local de la funcion la variable "a" no esta definida y entonces se le conoce como variable libre, sin embargo, al ejecutarse "filter" sobre la lista de albums, "a" toma un valor y puede ser accedido dentro el contexto de la funcion anónima, ésta captura de variables libres se le conoce como closure.

En general las funciones anónimas y los closures hacen a los programas más compactos y digestibles al eliminar mucha ceremonia en nuestro código.

Comentarios

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de arcioneo

Esperaba un tutorial o algo mas explicativo

Me equivoque

Aqui esta el