Novedades de Java 10

Escrito por el , actualizado el .
java planeta-codigo programacion
Enlace permanente Comentarios

Oracle y los ingenieros a cargo del desarrollo de Java están haciendo en mi opinión un buen trabajo que se han materializado en las versiones Java 8 con las lambdas, en Java 9 con los módulos y en Java 10 con la mejora en la inferencia de tipos. Todo ello está haciendo que la plataforma evolucione más rápido y significativamente que lo que hasta hace unos años estábamos acostumbrados.

Java

El 20 de marzo de 2018 se publicó la que es la versión 10 de Java siguiendo el nuevo calendario de publicar una nueva versión cada seis meses, Java 9 fue publicado en septiembre del año anterior. Con este nuevo calendario no pasarán tantos años entre cada nueva versión que era la queja de algunos desarrolladores y el motivo de que la plataforma Java no evolucionar tan rápidamente como algunos desarrolladores desean, quizá ahora la queja sea al contrario que se publican demasiadas versiones y no da tiempo a asimilar los cambios. Para dar cabida a ambas necesidades y garantizar un soporte prolongado cada año y medio será declarada una versión como de soporte a plazo largo o LTS para que las empresas tengan seguridad en las aplicaciones que desarrollen.

Lo mejor de este nuevo calendario de publicaciones cada seis meses es que las empresas y programadores tienen predictibilidad de cuándo se lanzará la siguiente versión aunque las nuevas características que tenga no está predeterminado ya no pasarán varios años entre versiones visibilizando que la plataforma evoluciona continuamente en pequeños saltos cada poco tiempo en vez de saltos grandes cada mucho tiempo que son más disruptivos y hace más difícil la adopción.

Introducción

En Java es un principio no añadir características según lo que está de moda sino pensando en décadas futuras. Java 10 tiene una lista más reducida de cambios que Java 9 pero importantes y significativos. Java es el último en unirse a la fiesta de la inferencia de tipos pero ha sido de forma intencionada ya que el coste de implementarla de forma incorrecta supone un alto coste que hay que mantener en adelante. Otras ideas que ha sido implementadas el lenguajes de programación funcional y están listas para su uso masivo tomarán su propio camino en futuras versiones de Java por ejemplo pattern matching y value types.

La lista más relevante de es la siguiente:

Nuevas características

Inferencia de tipos para variables locales

De las novedades la inferencia de tipos para variables locales es la más destacada en cuanto a cambios en el lenguaje con la adición de la nueva palabra reservada var, esto ayuda a no tener que repetir varias veces los tipos en la construcción de un objeto. En las lambdas los parámetros no es necesario declararlos infiriéndose de la interfaz que implementan. La inferencia de tipos es la idea que permite al compilador obtener el tipo estático sin que sea necesario escribirlo de forma explícita.

Java no es el único o primer lenguaje en incluir la inferencia de tipos para variables. Ha sido usado en otros lenguajes durante décadas. En realidad la inferencia de tipos incluida en Java 10 con var es muy limitada y restringida de manera intencionada. Si no fuese así el algoritmo Hindley-Milner usado para la inferencia de tipos usado en la mayoría de lenguajes que toma un tiempo exponencial en el peor de los casos potencialmente disminuiría la velocidad de javac.

La inferencia de tipos para variables locales hace que el código no sea tan verboso sin perder en gran medida la legibilidad ya que solo es para las variables locales. El siguiente ejemplo muestra la evolución de la inferencia de tipos desde Java 5 pasando por Java 8 donde se incluyeron algunas mejoras y el que puede utilizarse a partir de Java 10.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// Java 5
List<String> channels = Collections.<String>emptyList();

List<String> channels = Collections.emptyList();

// Java 7
Map<String, List<String>> userChannels = new HashMap<String, List<String>>();

Map<User, List<String>> userChannels = new HashMap<>();

// Java 8
Predicate<String> nameValidation = (String x) -> x.length() > 0;

Predicate<String> nameValidation = x -> x.length() > 0;

// Java 10
var userChannels = new HashMap<User, List<String>>();

var channels = lookupUserChannels("Tom");
channels.forEach(System.out::println);
JavaTypeInference.java

Los tipos en la parte izquierda pueden parecer redundantes y obvios. Tradicionalmente la filosofía de Java es declarar de forma estática los tipos para todo incluyendo las expresiones más simples. Ciertamente definir los tipos para propiedades y en las firmas de los métodos impone un contrato que es necesario respetar y esto ayuda en el mantenimiento asi como a su entendimiento. Sin embargo, declarar los tipos para expresiones intermedias puede parecer menos útil e incómodo.

En el artículo Java 10 Local Variable Type Inference y vídeo de Youtube First contact with ‘var’ in Java 10 hay una explicación más detallada de esta nueva característica y se aprecia claramente en los siguientes ejemplos que muestran la evolución de la inferencia de tipos.

No solo hay una mejora de legibilidad aquí, también hay una ventaja en términos de evolución y mantenimiento de código. Si tomamos el mismo código con tipos explícitos para la variable userChannels y reemplazamos el tipo del canal representado con un String con un objeto de dominio Channel que pudiese tener información adicional acerca del canal entonces necesitaríamos reescribir los tipos de todo el código que dependa de este nuevo tipo.

La inferencia de tipos definitivamente reduce la cantidad de tiempo para escribir código Java pero mejor es la mejora en legibilidad del código. Los desarrolladores dedican mucho más tiempo a leer código fuente que el que dedican a escribirlo de manera que definitivamente hay que optimizar para la facilidad de lectura sobre la facilidad de escritura. Aunque var no siempre es una mejora en cuanto a legibilidad ya que se pierde la información del tipo su uso se guía por el principio de no tanto para optimizar la escritura o lectura sino generalizando más para la facilidad de mantenimiento, escribir algunos tipos genéricos no triviales es complicado aún con la ayuda de asistencia de un entorno integrado de desarrollo.

No está permitido en retornos, parámetros, propiedades, variables sin inicializar, ni asignar null pero en Java 11 el uso de var se permitirá en los parámetros de una expresión lambda que será útil porque permite un parámetro formal cuyo tipo es inferido pero que además en el que se pueden usar anotaciones.

1
2
(@Nonnull var x, var y) -> x.process(y)

JavaLambdaVarAnnotation.java

Con la inferencia de tipos los nombres de las variables cobran mayor importancia dado que var elimina la posibilidad al lector del código adivinar la intención de una variable a partir del tipo. Ya es difícil asignar nombres adecuados ahora supondrá mayor importancia.

El tipo en las variables locales no es tan importante ya que normalmente los nombres de las variables son el del tipo. Con var se evita repetición entre el tipo y el nombre de la variable, la brevedad de var hace destacar el nombre de la variable y proporciona mayor claridad además de tener que escribir menos código repetitivo.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// Java 9
Class.forName("org.postgresql.Driver");
Connection connection = DriverManager.getConnection("jdbc:postgresql://localhost/database", "user", "password");
PreparedStatement statement = connection.prepareStatement("select * from user");
ResultSet resultSet = statement.executeQuery();

// Java 10
Class.forName("org.postgresql.Driver");
var connection = DriverManager.getConnection("jdbc:postgresql://localhost/database", "user", "password");
var statement = connection.prepareStatement("select * from user");
var resultSet = statement.executeQuery();
NamesAlign.java

Con var se evita la longitud variable de los tipos y la no alineación de los nombres de las variables, permite quitar los nombres largos de algunos tipos que son comunes en las aplicaciones empresariales como cosas como DefaultListenerFactory con vocablos que se van añadiendo uno detrás de otro hasta formar un largo nombre.

Utilizar var no tiene por que suponer una perdida de legibilidad del código, un buen nombre de variable da más información que el tipo. Por ejemplo, List<User> parece ser una lista de usuarios, utilizando el nombre de la variable admins obtendríamos que son una parte más concreta de usuarios en el contexto local en el que se está usando. Por lo que no tener el tipo no es dramático si es suplido con un buen nombre de variable que capture su contenido correctamente.

La palabra reservada var no hace de Java un lenguaje dinámico, sigue siendo estático y fuertemente tipado. Solo que ahora los tipos no hace falta declararlos explícitamente y es el compilador el que se encarga de inferirlos según el contexto. En tiempo de ejecución nada cambia, el rendimiento sigue siendo el mismo y solo es una característica en tiempo de compilación.

La existencia de var no significa que haya de usarse de forma indiscriminada para todas las variables locales sino juiciosamente. En este caso quizá es preferible declarar el tipo por no ser obvio lo que retorna el método getCities().

1
2
Map<String, List<City>> countryToCities = getCities();
var countryToCities = getCities();
TypeVsVar.java

Los entornos integrados de desarrollo tardarán un tiempo en implementar la inferencia de tipos para variables locales hasta que lancen nuevas versiones.

Otras novedades

El tiempo para iniciar el interprete REPL de JShell ha sido reducido significativamente especialmente en casos donde se inicia con un archivo que incluye varios snippets.

Se han añadido mejoras en la herramienta de documentación de las clases Javadoc como soporte para varias hojas de estilo, agrupar métodos redefinidos que no cambian la especificación o nueva etiqueta summary como resumen de la API.

Se han añadido varios métodos para crear copias no modificables con List.copyOf(), Set.copyOf(), and Map.copyOf(). Se han añadido nuevos métodos a la clase Collectors para devolver una lista no modificable con toUnmodifiableList, toUnmodifiableSet, and toUnmodifiableMap.

Se añade el método Optional.orElseThrow().

Algunas otras características ya obsoletas se han eliminado y otras se han marcado como deprecated.

El posible futuro JDK 11+

Está planificado en seis meses después de Java 10 y con soporte extendido, el soporte de Java 10 durará tan solo hasta 2018.09, el de Java 11 al ser una LTS durará un periodo de 8 años hasta el 2026.09.

En el nuevo modelo las nuevas características no se añaden hasta que están preparadas. Tentativamente las características de JDK 11 no están completamente determinadas pero se están evaluando grandes proyectos como Valhalla para hacer más eficiente el tratamiento de datos que no requieran la identidad de objetos con los denominados Value Types útil para la programación funcional con datos puros optimizados para computaciones en paralelo. El proyecto Loom que posibilita una versión más ligera aún que los threads o hilos con fibers o fibras, continuations o coroutine y Tail Call. El proyecto Panama hará más fácil trabajar con código nativo o el proyecto ZGC para crear un recolector de basura que pueda manejar gigabytes y terabytes con pausas menores a 10ms. O el proyecto Amber con unas pequeñas mejoras pero muy cómodas para el programador como la de los literales strings raw. En la página del OpenJDK hay más proyectos que en un futuro quizá sean implementados y publicados en alguna versión.

En la sección final de referencia incluyo varios artículos y vídeos de los que he obtenido la información para hacer este resumen de las novedades de Java 10. Algunos son muy interesantes y amplían en gran medida lo comentado y lo que posiblemente llegue en un futuro.


Comparte el artículo: