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í:
[java] <p style="text-align: justify;">public Integer sum(Integer a, Integer b) {
return a + b;
}</p> [/java]
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:
…
if (filter.getName() != null) {
query.and("name =" + filter.getName());
}
if (filter.getEmail() != null) {
query.and("email =" + filter.getEmail());
}
…
}</p> [/java]
Que se podría refactorizar a algo así:
[java] <p style="text-align: justify;">public <T> void IfNotNull(T item, Consumer<T> consumer) {if (item != null) {
consumer.accept(item);
}
}</p>
<p style="text-align: justify;">public void query(Filter filter) {
…
ifNotNull(filter.getName(), name -> query.and(‘name =’ + name);
ifNotNull(filter.getEmail(), email -> query.and(‘email =’ + email);
…
}</p> [/java]
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.
Deja una respuesta