Lo "nuevo" en Java 8 (Java Standard Edition)
Oracle ha liberado recién la nueva versión de Java. En casi 20 años de historia el lenguaje dispone de 8 versiones y de innumerables actualizaciones para cada una de las que han existido. Sigo el lenguaje desde que nació y lo he usado para varias cosas, entre ellas para enseñar programación orientada a objetos cuando el sombrero que llevo puesto es el de profesor.
Escribo entre comillas la palabra nuevo para satisfacer a aquellos que consideran que no hay innovación alguna en las cosas que en la nueva versión se introducen. Casi siempre se cumple eso de que "no hay nada nuevo bajo el sol", pero siempre se recibe son agrado si los que diseñan el lenguaje que usas para ganarte el pan de cada día, incorporan a ese lenguaje las cosas buenas que otros han incorporado. Sucede aunque con menos frecuencia, que también se incorporan cosas malas.
Oracle siempre documenta lo nuevo de Java categorizando en varios rubros lo que incorpora al lenguaje. Voy a tomar esa categorías para comentar aquí un resumen de lo incorporado y en este post comentaré lo que concierne al lenguaje. En posts subsiguientes me referiré a otras cosas, y en otros que sigan si no canso al lector ilustraré todas esas "novedades" con ejemplos.
Expresiones lambda
Son bastantes los lenguajes que han incorporado las expresiones lambda en su diseño. Lenguajes algo lejanos a la programación funcional como C++ y C# ya lo han hecho y casi todos los lenguajes que hoy se inventan tienen esa construcción como uno de sus requerimientos. Sin entrar mucho en el meollo de toda la teoría que rodea al cálculo lambda, podemos con cierto riesgo decir que una expresión lambda es un bloque de código que puede ser manipulado como una función sin necesidad de atarla a un identificador y que es posible manipularla en el lenguaje como se manipula cualquier otro valor u objeto si así se prefiere entender (funciones como ciudadanos de primera clase). Se usan varios términos para referirse a lo mismo, entre ellos, función anónima, literal función y constante función son de los que más abundan.
De nada serviría dar soporte en el lenguaje a esa construcción si esos bloques no pudieran ser tratados como valores: asignarlos a variables, pasarlos como argumentos a funciones, ser retornados como funciones, etc. Y entre todas esas cosas, la que sobre sale es la de que el lenguaje permita diseñar funciones de orden superior (forma funcional, funcional, functor); funciones que al menos permiten recibir como entrada funciones y devolver funciones como salida. Una vez que se tiene ésto, es posible entonces enriquecer el diseño del programa con los famosos closures o clausuras, a los cuales me referiré en otro post.
Esa necesidad de pasar como argumento un bloque de código a un método de algún objeto siempre ha estado presente en las aplicaciones que se escriben con Java y cualquier otro lenguaje. El ejemplo que casi todo el mundo utiliza para hacer evidente esa necesidad es en el procesamiento de eventos y, en ese contexto casi siempre se toma a Swing como el escenario típico. Desde sus inicios, Java nos ha "obligado" a hacer eso con clases anónimas que implementan alguna interfaz funcional de manera directa o indirecta (indirecta cuando heredamos de alguna clase que ya brinda implementación por default para algunos métodos). Muchos consideran que esa técnica es demasiado verbosa, lo que puede ser cierto en algunos casos y falso en otras situaciones. Lo importante a destacar es que realmente lo que hacemos cuando usamos esa técnica es porque tenemos la necesidad de hacerle llegar al método un bloque de código que el objeto que procesa ese método requiere para completar su trabajo. En esencia, pasar una función o bloque de código que pueda ser tratado con independencia y al cual se le pueda asignar un tipo.
Sigue el ejemplo casi "canónico"
Como es conocido,
es una interfaz funcional (la descripción de una acción específica que debe ser implementada por quien quiera usarla). Esa acción o código como queramos llamarla es lo que requiere el objeto
para realizar su trabajo. Las expresiones lambda llegan en su auxilio y la porción de código anterior, podemos escribirla ahora así:
¿Qué hemos logrado? Varias cosas y lo fundamental es que logramos mayor claridad en nuestra intención, que no es otra que hacerle llegar al objeto el bloque de código que es lo que realmente necesita. Por supuesto que hay otras cosillas en eso que hemos escrito, como la libertad de expresar el parámetro de entrada al bloque de código sin tener que indicar su tipo. Ya era hora que Java incluyera algo de inferencia de tipos, cuando es evidente.
Referencias a métodos
Sucede con bastante frecuencia que las expresiones lambda que escribimos, no hacen otra cosa que llamar a un método existente, bien de instancia o de clase. Podríamos entonces bautizar esa expresión lambda con el nombre del método que ella invoca, y usar ese nombre para referirnos a ella. Sigue un ejemplo
El predicado
se escribe para comprobar algunas de las propiedades de los números enteros. Usamos en el ejemplo la que escribimos y no la que ofrece el lenguaje. El propósito es no tener que meternos por lo pronto en los métodos de extensión virtual que esta última tiene.
Escribimos ahora una implementación de
para comprobar si el parámetro del método
es impar.
Escribimos ahora un filtro para crear una nueva lista que contenga solamente los números que satisfagan el predicado. El código es:
Escribimos ahora el código para filtrar los números enteros:
Otras "novedades" del lenguaje en Java 8 son: los métodos de default o métodos de extensión virtuales, mejoras en las anotaciones, un sistema de inferencia de tipos mejorado y algunas cosillas para usar reflexión sobre los parámetros de los métodos. Lo discuto en el post que seguirá a éste.
- bferro's blog
- Inicie sesión o regístrese para enviar comentarios
Algo sobre Java 8
Espero tener el siguiente post mañana.
revisando las novedades en
revisando las novedades en java 8 además de las interfaces funcionales y lambdas , hay que agregar además la nueva característica en la API de poder usar tantos métodos abstractos como implementados quisiéramos.
con esto las diferencias con las clases abstractas se han acortado y prácticamente tienen la misma utilidad a no ser claro por la herencia multiple que no es permitida , aquí un ejemplo :
Siguen siendo diferentes
Las interfaces con métodos de default siguen siendo diferentes a las clases abstractas. Escribiré sobre eso en mi siguiente post sobre Java 8.