¿Programación funcional en Java 8? 🤔🤔
Es interesante ver como java evolucionó permitiendo integrar funciones que pueden suplir a las clases, es decir se puede escribir código declarativo diciendo que se va hacer y no código con clases que implica el como se va hacer, y lo mas importante permite que este se adapte a tiempo de ejecución gracias a los Genericos, que identifican el tipo de variable con que se esta trabajando, pero entonces que pasaría si al final no arroja el tipo de dato que estamos buscando sino un null 😫😫 aquí mágicamente aparece otra característica que son los Optional que identifica si existe o no un dato 🤯🤯, de esta manera puedes respaldar el código que escribes sin necesidad de que este contenga exceptions innecesarios.
La maravilla se encuentra en que esto se vuelve como un juego de legos en que tu vas acomodando las piezas que necesitas y como lo necesitas, acortando así el total de código que vas a escribir.
¿Qué son Lambdas? 🤨🤨
Estos nacen gracias a la nueva anotación de @FunctionalInterface que permite a las interfaces tener un método abstracto diferente a los definidos por Object (equals, hashcode, clone, etc) de manera que se pueda trabajar con funciones más explícitas y anonimas (Lambdas). Entonces, los lambdas son la manera en que Java ha encontrado para que se puedan escribir funciones anónimas sin necesidad de clases o instancias, de rápida ejecucción siendo lo mas transparente para el programador.
Existen 4 grandes grupos de interfaces funcionales ✍:
- Predicate: Devuelve a fuerzas un boolean y normalmente es usada para validación de criterios (filtrar).
- Supplier: Este tipo genera objetos sin que tenga argumentos.
- Consumer: Es usada para consumir métodos del parámetro T (argumento que se pasa) causando así posibles efectos secundarios.
- Function: Es usada para convertir de un parámetro de tipo T a otro de tipo R.
Este tipo de funciones tienen variantes y se explican a más detalle en java.util.function encontrarás el link de la documentación en la bibliografía.
La forma en que podemos escribir Lambdas son de esta manera:
(a,b) -> Integer.sum(a,b)
(a,b) -> {
System.out.println("Los número a sumar son: " + a + " " + b);
return Integer.sum(a,b)
}
Como se nota cuando hay más de una línea de código se utiliza corchetes, además que se debe retornar el tipo de dato que se necesite o espere según sea el caso.
Métodos de referencia 😎😎
A menudo encontrarás forma de escribir funciones lambdas un tanto particular y es que existen 3 casuísticas y otra con constructores que permiten acortar aún más el código.
1.- Métodos estáticos
Los métodos estáticos son aquellos que puedes invocar sin necesidad de instanciar un objeto específico de la clase. Para utilizar su referencia sería de esta manera NombreClase::métodoEstático.
- Ejemplo sin referencia
BinaryOperator<Integer> sum = (a,b) -> Integer.sum(a,b);
- Ejemplo con referencia
BinaryOperator<Integer> sum = Integer::sum;
2.- Instancia de un objeto
Cuando se cuenta con una referencua a un objeto y se desea invocar alguno de sus métodos de instancia dentro de la expresión lambda, sería de esta manera RefObjeto::métodoInstancia. Por ejemplo, la clase java.lang.System tiene una referencia a un objeto de tipo java.io.PrintStream denominada out, usaremos esa referencia para el siguiente ejemplo.
- Ejemplo sin referencia
Consumer<Integer> print = (a) -> System.out.println(a);
- Ejemplo con referencia
Consumer<Integer> print = System.out::println;
La referencia al objeto se tiene en System.out y se invoca su método de instancia println(int): void
3.- Instancia de algún tipo
Se parece al anterior, aunque se diferencia en que no hay una referencia a un objeto, solo se conoce su tipo y se podría escribir una expresión lambda así Tipo::métodoInstancia.
- Ejemplo sin referencia
Comparator<String> upper = (a, b) -> a.compareToIgnoreCase(b);
- Ejemplo con referencia
Comparator<String> upper = String::compareToIgnoreCase;
4.- Constructores
Se puede abreviar para los constructores ser escritos de esta manera Clase::new
- Ejemplo sin referencia
Function<Integer, List> listSupplier = (num) -> new ArrayList();
- Ejemplo con referencia
Function<Integer, List> listSupplier = ArrayList::new;
También podrían usarse los métodos de una clase sin que sean estáticos Clase::método esto serviría para cuando se desea obtener un valor específico para elaborar un stream. Para ello se tiene una lista de personas.
- Ejemplo sin referencia
IntStream edades = personas.stream().mapToInt(p -> p.getEdad());
- Ejemplo con referencia
IntStream edades = personas.stream().mapToInt(Persona::getEdad);
Conclusión
Se ha revisado temas como:
- De donde provienen los lambdas y que aportan al momento de escribir código.
- Los tipos de funciones que se puede escribir, además de otras variedades que nos ofrecen en la documentación.
- Se ha conocido los métodos de referencia que permiten acortar el código sin que llegue a ser tan verboso.
Tal como lo hemos visto aún quedaría la duda de donde usarlo o lo mejor de todo como usarlo, para ello existen los Stream que son su complemento perfecto, con calma lectores que esta sería la primera parte de 3 artículos que esta relacionados entre sí, esta primera parte consta de explicar los Lambdas, para luego explicar que son los Stream y concluir con ejercicios o casuísticas donde pueden ser aplicados estos conceptos.
Bibliografía
- https://www.oracle.com/mx/technical-resources/articles/java/expresiones-lambda-api-stream-java.html
- https://www.oracle.com/mx/technical-resources/articles/java/expresiones-lambda-api-stream-java-part2.html
- https://www.oracle.com/lad/technical-resources/articles/java/processing-streams-java-se8.html
- https://www.arteco-consulting.com/post/introduccion-a-java-lambda
- https://github.com/acelopezco/lambdas-lab/blob/master/src/main/java/com/javanme/java8/Avanzado.java
- https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html
Top comments (0)