Translate

sábado, 19 de septiembre de 2026

Java 27: hacia dónde está evolucionando Java

 


Java cambió hace tiempo su ritmo de evolución.

Ya no tenemos que esperar varios años para ver cambios importantes en el lenguaje. Desde Java 10, el JDK recibe una nueva versión cada seis meses.

Y esto produjo algo interesante: las grandes funcionalidades dejaron de aparecer todas juntas y comenzaron a evolucionar durante varias versiones.


Un buen ejemplo son los patrones, la concurrencia estructurada, los valores lazy o las mejoras de rendimiento de la JVM.

Java 25, Java 26 y Java 27 muestran bastante bien hacia dónde está avanzando el lenguaje.


Java 25: un nuevo LTS

Java 25 llegó en septiembre de 2025 y es una versión LTS.

Entre sus novedades hay cambios tanto en el lenguaje como en la JVM y las bibliotecas.


Archivos fuente más simples: Java 25 incorporó los Compact Source Files and Instance Main Methods.

Ahora un programa pequeño puede escribirse de una manera mucho más sencilla:


void main() {

    System.out.println("Hello Java!");

}


Ya no es necesario comenzar con:


public class Main {

    public static void main(String[] args) {

        System.out.println("Hello Java!");

    }

}


La idea no es crear un nuevo lenguaje para principiantes, sino permitir que Java pueda comenzar siendo pequeño y crecer posteriormente hacia el modelo tradicional.


Module Import Declarations


También apareció:

import module java.base;


En lugar de importar individualmente paquetes como:


import java.util.*;

import java.io.*;

import java.nio.*;


se puede importar todo lo exportado por un módulo.


Es especialmente interesante para programas pequeños y ejemplos, donde el ruido de los imports puede ser considerable.


Flexible Constructor Bodies


Java también flexibilizó los constructores.


Antes:

class Person extends Entity {


    Person(String name) {

        super(name);

    }

}


El constructor tenía que comenzar con super(...) o this(...).


Java 25 permite realizar ciertas operaciones antes de esa invocación explícita:


class Person extends Entity {


    Person(String name) {

        name = name.trim();


        super(name);

    }

}



Esto permite validar o preparar datos antes de construir la parte correspondiente a la superclase.


Scoped Values


Otra característica importante de Java 25 fue Scoped Values.

Son una alternativa a ThreadLocal para compartir datos inmutables dentro de un contexto de ejecución.

Esto resulta especialmente interesante cuando se combinan con Virtual Threads y Structured Concurrency.

Es decir, Java empieza a construir un modelo de concurrencia más coherente alrededor de estas nuevas abstracciones.


Y la JVM también sigue cambiando


Java 25 no fue solamente lenguaje.

Por ejemplo, incorporó Compact Object Headers, que permiten reducir el tamaño de las cabeceras de los objetos en arquitecturas de 64 bits.

También continuó el trabajo de Project Leyden, orientado a mejorar startup y warmup mediante mecanismos AOT.


Java 26: menos sintaxis, más JVM

Java 26 llegó en marzo de 2026.

A diferencia de Java 25, no es una versión LTS, pero continuó varias de las líneas iniciadas en versiones anteriores.

Una de las novedades más interesantes fue HTTP/3 en el HTTP Client API.

El cliente HTTP de Java ahora puede trabajar con HTTP/3 sin necesidad de utilizar una biblioteca externa específica para ese protocolo.


Por ejemplo, seguimos teniendo una API similar a:


HttpClient client = HttpClient.newHttpClient();


HttpRequest request =

    HttpRequest.newBuilder(uri)

        .build();


HttpResponse<String> response =

    client.send(request, BodyHandlers.ofString());


pero el JDK amplía las posibilidades de transporte disponibles.

Esto es especialmente interesante para aplicaciones Java que funcionan como clientes de APIs y microservicios.


Project Leyden sigue avanzando

Java 26 continuó el trabajo de AOT Object Caching.

La JVM puede almacenar objetos previamente inicializados en una caché AOT y reutilizarlos durante el arranque.

La diferencia importante es que Java 26 permite hacerlo independientemente del Garbage Collector utilizado, incluyendo ZGC.


La dirección es clara: Java quiere arrancar más rápido sin abandonar el modelo dinámico de la JVM.


Java 26 también incorporó mejoras al Garbage Collector G1 para reducir sincronización y aumentar el throughput.

Y esto prepara el terreno para Java 27, donde G1 pasa a ser el GC predeterminado en todos los entornos.


Java 26 también comenzó a preparar un cambio importante relacionado con los campos final.

El JDK empezó a emitir advertencias cuando se utiliza reflexión profunda para modificar campos final. La intención es avanzar hacia un Java donde final signifique realmente que el campo no puede modificarse mediante estos mecanismos.

Es otro ejemplo de una tendencia importante de integridad y optimización por defecto.


Y llegamos a Java 27

Java 27 continúa muchas de estas ideas.

No es una revolución sintáctica.

De hecho, es bastante más interesante observar qué problemas está intentando resolver.


Entre las principales novedades de Java 27 encontramos nueve JEPs, incluyendo características definitivas y varias que continúan como preview o incubator.


Compact Object Headers por defecto

Java 25 introdujo los Compact Object Headers como una funcionalidad que había que activar explícitamente.

Java 27 da el siguiente paso:pasan a estar habilitados por defecto.

La cabecera tradicional de un objeto podía ocupar 96 bits en determinadas configuraciones.

Con Compact Object Headers puede reducirse a 64 bits.

Esto significa menos memoria por objeto y potencialmente mejor densidad de datos en el heap.

Y lo interesante es que:no necesitamos modificar nuestro código.

Es una mejora de la JVM.


G1 pasa a ser el Garbage Collector por defecto en todos los entornos

G1 ya era el Garbage Collector predeterminado desde Java 9 en la mayoría de los casos.

Java 27 elimina las excepciones para máquinas pequeñas.

Ahora G1 pasa a ser el GC por defecto independientemente de la cantidad de CPU o memoria disponible.


Esto muestra otra tendencia: La JVM cada vez necesita menos configuración manual para obtener un comportamiento razonable.


Structured Concurrency sigue evolucionando

Structured Concurrency aparece nuevamente en Java 27 como séptimo preview.

La idea es tratar un conjunto de tareas concurrentes como una única unidad de trabajo.

Por ejemplo, imaginemos que para construir una respuesta necesitamos consultar:


              ┌── usuario

              │

Request ┼── pedidos

              │

              └── recomendaciones


Podemos ejecutar las tres operaciones concurrentemente.

Pero queremos que tengan una relación estructurada:

  • si una falla, podemos cancelar las demás;
  • esperamos a que terminen;
  • propagamos correctamente los errores;
  • no dejamos tareas ejecutándose accidentalmente.


Ese es precisamente el tipo de problema que Structured Concurrency intenta resolver.

Y tiene una relación natural con Virtual Threads.

Java no está solamente haciendo que crear threads sea barato.

Está intentando mejorar la forma en que pensamos la concurrencia.


Lazy Constants

Los Stable Values de Java 25 evolucionaron en Java 26 hacia Lazy Constants y continúan evolucionando en Java 27.


La idea es interesante: queremos un valor que sea inmutable después de inicializarse, pero cuya inicialización pueda retrasarse hasta que realmente sea necesario.


Conceptualmente:


LazyConstant<Connection> connection =

    LazyConstant.of(() -> createConnection());


La conexión no se crea necesariamente al construir el objeto.

Se crea cuando realmente se necesita.

Y una vez inicializada, permanece estable.

Es una forma más limpia de resolver ciertos casos que tradicionalmente terminábamos implementando con inicialización lazy, sincronización o double-checked locking.


Primitive Types + Pattern Matching


El pattern matching continúa su evolución.

Java 27 vuelve a presentar como preview la posibilidad de trabajar con tipos primitivos dentro de instanceof, switch y patrones.

Es la continuación de una evolución que comenzó varias versiones atrás.

La dirección es bastante clara:


switch (value) {

    case int i -> ...

    case long l -> ...

}


La intención es que el sistema de pattern matching sea cada vez más uniforme y no tenga una separación artificial entre tipos referencia y tipos primitivos.


Criptografía preparada para el mundo post-cuántico

Java 27 también incorpora soporte para Post-Quantum Hybrid Key Exchange en TLS 1.3.

La idea es combinar algoritmos tradicionales con algoritmos resistentes a ataques cuánticos.

Esto apunta a un problema que hoy parece lejano, pero que en seguridad ya se considera relevante: harvest now, decrypt later.


Un atacante puede almacenar tráfico cifrado hoy y tratar de descifrarlo en el futuro cuando disponga de tecnología suficiente.

Java empieza a preparar la infraestructura criptográfica para ese escenario.


JFR puede ocultar información sensible

Java Flight Recorder también recibe una mejora importante.

Java 27 incorpora JFR In-Process Data Redaction.

La idea es evitar que información sensible presente en argumentos, propiedades o variables de entorno termine accidentalmente en una grabación de JFR.


Por ejemplo:

PASSWORD=...

TOKEN=...

API_KEY=...


El objetivo es mejorar la observabilidad sin convertir los mecanismos de diagnóstico en una nueva fuente de filtraciones.


Entonces, ¿hacia dónde está evolucionando Java?

Si miramos Java 25, 26 y 27 en conjunto, aparece una imagen bastante interesante.

Java no está intentando convertirse en otro lenguaje.

La JVM intenta hacerse más inteligente para que el código Java pueda permanecer relativamente simple.

También consiste en conseguir que el mismo código Java sea más rápido, consuma menos memoria, arranque antes, sea más seguro y sea más fácil de escribir.


Y Java 27 continúa exactamente en esa dirección.


No hay comentarios.:

Publicar un comentario