A partir de JDK 9, Java se actualiza con una nueva versión cada 6 meses. Las versiones LTS (Long-Term-Support) como Java 8/11 salen cada tres años y se van actualizando hasta
la siguiente versión LTS.
Desplegar las aplicaciones en contenedores facilita la actualización la versión de Java porque solo hay que actualizar la imagen para incluir un nuevo JDK y
no es necesario reinstalar el JDK en muchos equipos.
Java 9
Sistema modular (proyecto Jigsaw)
El sistema modular introducido en Java 9, probablemente el mayor cambio en la plataforma desde su inicio, proporciona capacidades similares al sistema OSGi.
Ahora es posible, pero no obligatorio, crear software compuesto por módulos que declaran una API pública y establecen relaciones de dependencia con otros módulos.Un módulo tiene un nombre, incluye una lista de paquetes de acceso público y puede incluir la declaración de dependencias hacia otros módulos. A partir de Java 9, todas las clases que son parte del classpath pero que no son parte de un paquete incluido en algún módulo, forman un módulo con nombre ‘unnamed’ que implícitamente depende de todos los módulos incluidos en el JDK.
Este enfoque modular ha sido aplicado a la librería estándar para facilita su evolución/mantenimiento permitiendo eliminar módulos/paquetes considerados obsoletos en lugar de incrementar permanentemente el número de paquetes a medida se publican nuevas versiones de Java.
A la hora migrar un proyecto basado en un JDK monolítico (Java 8 o anterior) a JDK modularizado (Java 9 o posterior) podemos encontrar dos problemas:
- El proyecto depende de clases que ahora han sido encapsuladas (esos paquetes son ahora privados). En este escenario se debe actualizar el código y las librerías del proyecto con el apoyo de herramientas como jdeps y maven(
mvn versions:display-dependency-updates
) - El proyecto depende de clases en paquetes que no son parte los módulos incluidos por defecto (aquellos incluidos como dependencia del módulo java.se).
En el siguiente vídeo se explica cómo abordar estos problemas.
API para gestión de procesos
El API de procesos se ha mejorado el control y gestión de procesos del sistema operativo. Las nuevas clases que son parte de esta mejora son java.lang.ProcessHandle
, java.lang.ProcessHandle.Info
Flow API
La clase java.util.concurrent.Flow
incluye interfaces que soportan el framework Reactive Streams. El propósito de estas interfaces es facilitar la interoperabilidad o migración entre varias implementaciones como RxJava, AkkaStreams o Spring Project Reactor.
StackWalker/StackFrame
Clases que facilitan el acceso y análisis de los elementos en la pila de llamadas.
JShell
Entorno interactivo (REPL) similar a los incluidos en lenguages como Python o Scala. Permite evaluar declaraciones y expresiones de Java, junto con una API.
Es muy conveniente para probar pequeños fragmentos de código, que de lo contrario requieren la creación de una nueva clase con el método principal.
Mejoras en APIs existentes
- Collections, métodos factory para crear instancias inmutables:
List.of
,Set.of
yMap.of
,Map.ofEntries
- Streams,
Stream.ofNullable
,Stream.takeWhile
,Stream.dropWhile
- Optional,
Optional.or
,Optional.stream
- try-with-resources, ya no requiere la declaración de una variable (siempre que esa sea final o efectivamente final).
- Programación genérica, el operador <> ahora se puede emplear con clases anónimas (anonymous inner classes).
- Interfaces, pueden tener métodos privados para facilitar la reutilización de código en los métodos default.
- java.time,
Duration.truncatedTo
,LocalDate.datesUntil
Referencias
Java 10
Inferencia del tipo de datos para variables locales (var)
Permite emplear el tipo var
para inferir el tipo de una variable a partir de lado derecho de una asignación. Debe emplearse siempre que el tipo de dato de la expresión en el lado derecho en una asignación sea evidente; es decir, en situaciones en las que mencionar el tipo de dato en la declaración de la variable es redundante.
Application Class-Data Sharing (ACDS)
En Java 10+, esta funcionalidad permite reducir al tiempo de arranque de la JVM cargando las clases directamente desde un archivo. Los arranques posteriores de la JVM o de otras JVMs que corran la misma aplicación requerirán menos tiempo.
Detección de contenedor
La JVM puede detectar si se ejecuta en un contenedor Docker y es capaz de extraer la configuración específica del contenedor en lugar de consultar el sistema operativo; se aplica a métricas como la cantidad de CPUs y la memoria total asignadas al contenedor. Sin embargo, este soporte solo está disponible para plataformas basadas en Linux.
Referencias
OpenJDK 10 Now Includes Root CA Certificates
Java 10 LocalVariable Type-Inference
Java 10 Performance Improvements
Java 11
Herramientas
Java Flight Recorder (JFR) y JDK Mission Control (JMC) ahora son herramientas Open Source. JFR es una herramienta para realizar profiling sobre el desempeño y uso de recursos de una aplicación Java. Por ejemplo, para iniciar una grabación JFR de 120 segundos, podemos usar el siguiente parámetro al iniciar Java
-XX:StartFlightRecording=duration=120s,settings=profile,filename=java-demo-app.jfr
Se puede emplear JFR en producción puesto que la carga general suele ser inferior al 1%. Una vez transcurrido el tiempo, podemos emplear JMC para analizar y visualizar los dato del archivo JFR.
Ejecución de archivos Java.
Ya no es necesario compilar un archivo Java antes de ejecutarlo.
HttpClient API
Ofrece un API para establecer conexiones síncronas y asíncronas empleando HTTP/1.1, HTTP/2 o WebSockets. Clases importantes:
- HttpClient/HttpClient.Builder
- HttpRequest/HttpRequest.Builder
- HttpResponse
Mejoras en APIs existentes
- Eliminación de los siguientes paquetes:
- java.xml.bind (JAXB)
- java.xml.ws (JAX-WS)
- java.xml.ws.annotation (JAX-WS Annotations)
- java.corba (CORBA)
- java.transaction (JTA)
- java.activation (JavaBeans Activation)
- Eliminación de los siguientes métodos:
- Thread.destroy
- Thread.stop(Throwable obj)
- System.runFinalizersOnExit
- Runtime.System.runFinalizersOnExit
- JavaFX ya no es parte del SDK y debe ser incluido como dependencia de manera explícita.
- Applets y Java Web Start ya no son parte de JDK.
- String, se agregaron los siguientes métodos:
isBlank
,lines
,strip
(soporta caracteres del espacio Unicode),stripLeading
,stripTrailing
yrepeat
. - Files, se agregaron los siguientes métodos:
Files.readString
,Files.writeString
para facilitar la lectura/escritura de archivos de texto. - Programación funcional:
Predicate.not
,Optional.isEmpty
.
Referencias
Java 12
Formato de número compacto
La clase CompactNumberFormat
está diseñada para representar un número en una forma más corta, basada en los patrones proporcionados por una Locale determinado.
Mejoras en APIs existentes
- String: nuevos métodos
indent
,transform
- Files:
Files.mismatch
compara dos archivos y retorna la posición del primer byte no coincidente en su contenido. - Programación funcional:
Collectors.teeing
permite aplicar dos collectors al mismo tiempo y combinar sus resultados.
Java Micro-benchmarking harness (JMH)
El alcance o nivel del micro benchmarking empleando esta herramienta está al nivel de los métodos y permite comparar alternativas para tomar la mejor decisión de diseño en secciones de código que se ejecutan con mucha frecuencia y tomar decisiones en aspectos como los siguientes:
- Apoyarse en el garbage collector o emplear pooling (reusar objectos)
- Atrapar un error o verificar el estado antes de ejecutar una sección de código. (if vs. try-catch)
- Evitar regresiones en el desempeño de métodos críticos y seleccionar las implementación con el mejor desempeño.
Puede crear un proyecto basado en JMH empleando el siguiente arquetipo Maven:
mvn archetype:generate -DinteractiveMode=false -DarchetypeGroupId=org.openjdk.jmh -DarchetypeArtifactId=jmh-java-benchmark-archetype -D<group-id> -DartifactId=<artifact-id> -Dversion=1.0
Como se muestra en el siguiente vídeo, las pruebas de desempeño se configuran empleando anotaciones:
Referencias
Compact Number Formatting Comes to JDK 12
Testing your code performance with JMH tool
Java 13
Mejoras en APIs existentes
- ByteBuffer: es una clase empleada en la API Java NIO. En Java 13 esta clase incluye mejoras en los métodos
get
yput
que hora soportan
el parámetroindex
que abre la posibilidad de leer/modificar la estructura desde varios hilos en lugar de sincronizar
el acceso al ByteBuffer. - Seguridad:
javax.security.cert
fue eliminado y las clases movidas ajavax.security.cert
- Localización: soporte de Unicode 12.1.
- Mantenimiento: reimplementación del API de sockets ((
java.net.Socket
,java.net.ServerSocket
). Si por alguna razón esto causa algún inconveniente es posible
emplear por algún tiempo más la implementación antigua pasando esta propiedad del sistema-Djdk.net.usePlainSocketImpl
Class-Data Sharing Dinámico (D-CDS)
Se introdujeron dos mejoras a esta funcionalidad introducida en Java 10:
Se facilita la creación de los archivos con la metadata de las clases que se quieren pre-cargar al iniciar la VM.
El siguiente comando configura la JVM para guardar en el archivo hello.jsa
la metadata de las clases Cuando la aplicación termine sin errores (exit code = 0):
java -XX:ArchiveClassesAtExit=hello.jsa -cp hello.jar Hello
Para cargar los archivos en otra JVM que corra con el mismo classpath:
java -XX:ArchiveClassesAtExit=hello.jsa -cp hello.jar Hello
Referencias
Java 14
Mejoras en APIs existentes
- PrintStream, se agregaron los siguientes métodos:
writeBytes
- Serialización: se agregó una nueva anotación
@java.io.serial
para la verificación en tiempo de compilación de declaraciones
relacionadas con la serialización. - Mantenimiento: se eliminó el paquete
java.security.acl
y se eliminaron las clasesjava.util.jar.Pack200.Packer
yjava.util.jar.Pack200.Unpacker
.
Mensajes NullPointerException
más detallados
Incluyendo la opción de línea de comando -XX:+ShowCodeDetailsInExceptionMessages
es posible generar información más detallada cuando se produce un NullPointerException
. Los mensajes generados son todavía más informativos cuando la compilación incluye la
opción para incluir más datos/símbolos de depuración (javac -g
)
En la parte inferior de la siguiente imagen se puede ver que el mensaje generado en Java 14+ incluye más detalles sobre la causa del error.
Expresiones switch
Introducidas en modo preliminar/preview en la versión 12, esta nueva característica del lenguaje permite emplear estructuras switch
para crear expresiones; es decir, para generar un valor que puede ser asignado a una variable, pasado como argumento o devuelto a/desde un método.
private static String platoADepartamento(String plato) { return switch (plato.strip().toLowerCase()) { case "soltero", "sullka", "karapecho", "mondongo" -> "Chuquisaca"; case "pique", "chajchu", "pampaku" -> "Cochabamba"; case "chairo", "fricasé" -> "La Paz"; case "charque" -> "Oruro"; case "majadito" -> "Santa Cruz"; case "saice" -> "Tarija"; default -> "desconocido"; }; }
Datos en tiempo real desde Java Flight Recorder
Con esta mejora, los datos generados por JFR se pueden consumir/monitorear continuamente. Esto implica modificaciones en el paquete jdk.jfr.consumer
para que los usuarios puedan leer o transmitir datos directamente de sde/hacia JFR.
Referencias
Java 15
Mejoras a APIs existentes
- PrintStream, se agregaron los siguientes métodos:
writeBytes
- Serialización: se agregó una nueva anotación
@java.io.serial
para la verificación en tiempo de compilación de declaraciones
relacionadas con la serialización. - Mantenimiento: se ha eliminado el soporte para plataformas Solaris/SPARC y el entorno de ejecución de JavaScript Nashorn para el cual existen algunas alternativas.
Mensajes NullPointerException
más detallados
En Java 15 ya no es necesario incluir la opción de línea de comando -XX:+ShowCodeDetailsInExceptionMessages
para activar esta funcionalidad.
Bloques de texto
Introducidas en modo preliminar/preview en la versión 13, esta nueva característica del lenguaje permite emplear cadenas de texto que se extienden por varias líneas directamente en el código fuente sin necesidad de incluir explícitamente caracteres de fin de línea y/o emplear concatenación de cadenas. Cuando el compilador detecta una cadena multi-línea en el código fuente, aplica ciertas transformaciones como la normalización del caracter de fin de línea y la eliminación de espacios innecesarios para que la cadena resultante sea la misma independientemente de la plataforma en la que se crea el código.
El caracter diagonal invertida/backslash puede emplearse para generar una cadena de una sola línea pero empleando varias líneas en el código fuente.
Finalmente, la clase String incluye nuevos métodos relacionados con manejo de bloques de texto: translateEscapes
, stripIndent
y formatted
.
String jsonString = """ { "nombre": "Marcelo", "apellido": "%s" } """.formatted("Rocabado");
Nuevos Recolectores de basura (Garbage Collectors)
En Java 15, tanto ZGC (JEP 377) como Shenandoah (JEP 379) dejarán de ser experimentales. Ambos recolectores están disponibles para su uso en producción, pero el recolector G1 seguirá siendo el predeterminado.
ZGC garantiza pausas de menos de 10ms en aplicaciones con memoria heap en el rango de 8Mb – 16TB!.
Referencias
Programmer’s Guide To Text Blocks
Understanding the JDK’s New Superfast Garbage Collectors
A categorized list of all Java and JVM features since JDK 8 to 16
Ripe for the picking: 11 essential Java features to help modernize your code
Comments are closed.