Hoy os voy a contar algo que os resultará de gran utilidad. Vamos a hablar de una mejora sobre la manera de utilizar funciones en este querido lenguaje: Java 8.
No seréis pocos los que hayáis echado de menos poder pasar funciones como parámetros o callbacks, que hasta ahora teníamos que usar, por ejemplo, con reflection.
Para ello, entran en juego dos nuevas amigas:
Interfaces funcionales
Son la base de las expresiones Lambda, y se definen como cualquier interfaz que tenga un único método (a parte de cualquier otro que extienda de Object).
Expresiones Lambda
O funciones anónimas. Son una manera de expresar una función sin tener que declararla de la manera habitual, sino con una notación más parecida a la matemática.
Así:
public Integer sum(Integer a, Integer b) {
return a + b;
}
Podría ser expresada como:
(a, b) -> a + b
Bastante más sencillo ¿verdad?
Ahora os propongo un caso práctico de un proyecto que he realizado últimamente.
Los métodos en los que tienes que construir una query en base a un objeto que contiene los filtros a aplicar, es muy común el siguiente patrón:
public void query(Filter filter) {
…
if (filter.getName() != null) {
query.and(“name =” + filter.getName());
}
if (filter.getEmail() != null) {
query.and(“email =” + filter.getEmail());
}
…
}
Que se podría refactorizar a algo así:
public <T> void IfNotNull(T item, Consumer<T> consumer) {
if (item != null) {
consumer.accept(item);
}
}
public void query(Filter filter) {
…
ifNotNull(filter.getName(), name -> query.and(‘name =’ + name);
ifNotNull(filter.getEmail(), email -> query.and(’email =’ + email);
…
}
No puedo dar por terminado mi post de hoy sin ofreceros el resumen de algunas de las Interfaces Funcionales que trae por defecto Java8, os salvará en más de una ocasión:
Runnable (void -> void): Ejecuta una acción sin argumentos y no devuelve nada.
Supplier<T> (void -> T): Ejecuta una acción que devuelve un valor de tipo T.
Consumer<T> (T -> void): Recibe un parámetro de tipo T y no devuelve nada.
BiConsumer<T, U> (T,U -> void): Recibe dos parámetros de tipo T y U y no devuelve nada.
Function<T, R> (T -> R): Recibe un parámetro de tipo T y devuelve un valor de tipo R.
BiFunction<T, U, R> (T, U -> R): Recibe dos parámetros de tipo T y U y devuelve un valor R.
UnaryOperator<T> (T -> T): Recibe un parámetro de Tipo T y devuelve un valor del mismo tipo.
BinaryOperator<T> (T, T -> T): Recibe dos parámetros de tipo T y devuelve un valor del mismo tipo. (El ejemplo de sum antes ilustrado entraría en esta categoría).
Predicate<T> (T -> Boolean): Evalúa el parámetro de tipo T a True/False.
Leave a Reply