Programación funcional
o también llamadas las expresiones lambda han supuesto un salto importante en la evolución del lenguaje.
En este artículo les vamos a compartir una breve introducción de cómo se usan y cómo escribir más con menos.
Funciones lambdas
Las funciones lambdas es un término adoptado de la programación funcional y corresponden con funciones de Java que normalmente son anónimas y se escriben en línea allí donde se usan. Como cualquier función, puede consumir métodos de otras clases y objetos. Al declararse al mismo tiempo en donde se usa, puede acceder a las variables locales del ámbito al que pertenece, pero sólo podrá usar estos como valores de sólo lectura, impidiendo realizar alguna modificación.
Las funciones lambdas fueron creadas a partir de la versión Java 8, por lo que no es posible usar su sintaxis en versiones anteriores. Sus entidades principales están contenidas en el package java.util.funcional. Sí hay que decir, que no aportan una funcionalidad que no pueda hacerse con Java pre 8, simplemente es una manera más compacta de escribir código Java.
Así que los que no dispongan de Java 8 podrían simular un comportamiento similar creando clases parecidas a las proporcionadas con el API de Java en el package java.util.functional.
Entidades de java.util.functional
Antes de crear una función de tipo lambda, conviene conocer las entidades básicas que componen esta manera de programar. Las principales entidades son interfaces con un único método que debe implementar el programador y que estas implementaciones pueden hacerse llegar como argumentos de métodos de otras muchas clases del API de Java. Hubo una gran modificación de las clases existentes para aceptar este tipo de implementaciones allí donde tuviera sentido, como ocurre en las colecciones.
Las implementaciones de estas interfaces son del tipo, consume un valor y retorna otro tipo de valor, o produce un valor sin argumentos o produce un valor dados dos argumentos. A éstas se les llama unidades funcionales porque componen una lógica interna que a priori el consumidor de esta lógica no conoce, pero de la que sí se conoce su interfaz y por tanto la manera de relacionarse con el resto de los objetos, o lo que es lo mismo la manera de ser invocada. Aparece de nuevo el concepto de cajas negras en donde entran parámetros y salen resultados.
Las interfaces funcionales más importantes contenidas en java.util.functional son:
- Supplier<T>: esta función se debe utilizar cuando se necesiten generar objetos sin requerir argumentos. Por ejemplo para realizar una inicialización perezosa.
- Consumer<T> esta en cambio es el opuesto de
Supplier
ya que consume, acepta como argumento el tipoT
sin devolver ningún valor de retorno. - Function<T,R> esta interfaz permite definir una función que acepta un parámetro de tipo
T
y devuelve un resultado del tipoR
pudiendo aplicarle alguna transformación u operación. - BiFunction<T,R,S> esta interfaz permite definir una función que acepta dos parámetros de tipo
T
yR
, devolviendo un resultado del tipoS
. Normalmente serán operaciones de agregación u operadores binarios como la suma, resta, etc.. - Predicate<T> la interfaz predicado debe devolver forzosamente un
boolean
dado un objeto de tipoT
, normalmente utilizado para filtrar elementos de una colección.
El paquete incluye más interfaces que el programador puede usar, pero estas son las más básicas con las que ya es posible empezar a realizar algunos ejemplos útiles y frecuentes.
Cómo se crea una funcion lambda
La sintaxis cambia un poco respecto a Java tradicional, ya que se intentan no escribir los tipos de las variables siempre y cuando no se cree alguna ambigüedad. Veamos el primer ejemplo:
Function<String,Integer> sizeOf = (String s) -> {
return s.length();
};
O su equivalente y más compacta:
Function<String,Integer> sizeOf = s -> s.length();
En ambos casos se está definiendo una función que dado un String
devolverá la longitud de la cadena de caracteres que almacene. Debemos fijar nuestra atención a que el tipo de la variable de s
se infiere automáticamente de los tipos utilizados en sizeOf
y que la palabra reservada return
no es necesaria, siempre y cuando no haya más de una sentencia en la función.
Por rara y compacta que pueda parecer la sintaxis, no es más que otra forma de escribir la siguiente clase, de hecho esto es lo que realmente genera el compilador:
public class SizeOf implements Function<String,Integer>{
public Integer apply(String s){
return s.length();
}
}
Así que para poder usar tanto la función sizeOf
como la clase SizeOf
en un bloque de código cualquiera, se realizaría de la siguiente forma:
Integer r1 = sizeOf.apply("hola java 8");
// o
Integer r2 = new SizeOf().apply("hola java 8");
La ventaja de hacerlo como función, en lugar de como clase, a parte de la reducción de los literales que acompañan a cada opción, es que el API del JDK de Java versión 8 y adelante tiene métodos que aceptan estas funciones, reduciendo aun más la cantidad de código que se debe escribir.
Por ejemplo veamos como podemos aplicar una ordenación usando un comparador escrito en Java 8:
class Persona{
String nombre;
Persona (String nombre){
this.nombre = nombre;
}
}
List<Persona> personas = new ArrayList<>();
personas.add(new Persona("Pepe"));
personas.add(new Persona("Andrés"));
personas.sort( (l, r) -> l.nombre.compareTo(r.nombre));
Esta última función lambda es una del tipo BiFunction
que acepta dos objetos de tipo Persona
y devuelve un int
típico de cualquier comparador de java java.util.Comparator<T>
. Tanto la función como el comparador son compatibles, así que la función lambda anónima, se podría haber guardado en una variable de tipo comparador para ser usado otra vez más adelante:
Comparator<Persona> comp = (l, r) -> l.nombre.compareTo(r.nombre));
personas.sort(comp);
Conclusiones
Desde luego hay muchas más opciones y funciones lambda que pueden usarse, este es sólo algunos ejemplos de cómo utilizar las más comunes.
Ahora que te presentamos esta información, es momento de continuar con ese roadmap para potenciar tu CV y destacar tu perfil en el sector de TI. Te invito a conocer metaphorce.mx, donde podras participar en los programas de formación y desarrollo para pertenecer a múltiples empresas de renombre global. Se parte de los programadores de alto nivel y promueve la transformación digital de las organizaciones.
Nuestro equipo provee de soluciones y conocimiento en tecnologías de la información, gobierno de TI y Desarrollo de soluciones a la medida para tu organización. De esta manera nuestros servicios de consultoría y transformación digital aceleran a tu organización a alcanzar sus metas. No dudes en contactarnos.
Te invitamos a continuar leyendo más de nuestros artículos. ¿Tienes alguna sugerencia o duda respecto a los servicios de consultoría y transformación digital para acelerar a tu organización y alcanzar tus metas? No dudes en contactarnos.
Autor: GHE
Comparte este artículo y síguenos en nuestras distintas Redes Sociales
¿Iniciamos?
Conoce todas las soluciones tecnológicas para acelerar
la transformación digital de tu organización.