Java 25: novedades, LTS y cuándo dejar Java 21

Por 2026-09-29
JavaJava 25LTSJDKMigraciónSpring BootBackend
Portátil con código en pantalla y una taza de café al lado, en una habitación con poca luz — novedades de Java 25
Foto de Daniil Komov en Pexels

Java 25 es la versión LTS vigente desde septiembre de 2025, y octubre de 2026 es el mes en que muchas empresas descubren que tienen que moverse: Oracle JDK 21 deja de actualizarse con licencia gratuita. Estas son las novedades de Java 25 que importan, lo que ganas y lo que se rompe viniendo de Java 21, y un orden sensato para migrar.

Las novedades de Java 25 se suelen contar como una lista de 18 JEPs. Esa lista es correcta y es poco útil: mezcla cambios que tocan el código que escribes cada día con experimentos que no deberías acercar a producción. Aquí van separadas por lo que te afectan.

Y hay un detalle que casi ningún resumen menciona: quien viene de Java 21 no recibe solo Java 25. Recibe también todo lo que se cerró en Java 22, 23 y 24, que nunca fueron LTS y que la mayoría de equipos se saltó. Parte de lo más valioso del salto está ahí.

Java 25 en una tabla: versiones, fechas y soporte

Antes de hablar de código, el calendario, que es lo que decide cuándo hay que moverse. Fechas de lanzamiento de OpenJDK y soporte según el calendario oficial de Oracle:

VersiónTipoPublicadaSoporte Premier (Oracle)Soporte Extended (Oracle)
Java 17LTSseptiembre 2021septiembre 2026septiembre 2029
Java 21LTSseptiembre 2023septiembre 2028septiembre 2031
Java 22 – 24no LTS2024 – 2025seis meses cada una—
Java 25LTS16 septiembre 2025septiembre 2030septiembre 2033
Java 26no LTS17 marzo 2026septiembre 2026—
Java 27no LTS15 septiembre 2026hasta la siguiente versión—

Tres conclusiones rápidas:

  • La última versión de Java es la 27, pero no es LTS. Para producción, la referencia es Java 25.
  • Java 17 ya ha salido de su soporte Premier en Oracle. Si sigues ahí, el salto natural es directo a 25.
  • Java 21 tiene soporte hasta 2028, pero con un matiz de licencia que explico más abajo y que para mucha gente es lo que marca la fecha.

Las novedades de Java 25 que cambian el código que escribes

Estas cuatro son definitivas (no preview): se usan sin flags y han venido para quedarse.

Clases y main sin ceremonia (JEP 512)

Un fichero Java ya puede ser solo esto:

void main() {
    IO.println("Hola, Java 25");
}

Sin clase, sin public static, sin String[] args. Se ejecuta con java Hola.java. La clase java.lang.IO trae println, print y readln para entrada y salida por consola, y todo el módulo java.base está disponible sin importar nada.

Parece una novedad para principiantes, y lo es. Pero también cambia cómo se escriben scripts de utilidad: migraciones de datos puntuales, comprobaciones de un fichero, pruebas de una librería. Antes eso se iba a Python o a Bash porque en Java «no merecía la pena montar el proyecto». Ahora un fichero suelto basta.

Importar un módulo entero (JEP 511)

import module java.base;

Importa de golpe todos los paquetes que exporta el módulo: java.util, java.io, java.time, java.util.stream… Es cómodo en scripts y prototipos.

En código de producción conviene usarlo con cabeza: si importas dos módulos que exportan la misma clase simple (el clásico List de java.util y de java.awt), el compilador te obliga a desambiguar con un import explícito. Nada grave, pero conviene saberlo antes de encontrárselo.

Constructores que validan antes de llamar a super() (JEP 513)

Hasta Java 24, super(...) tenía que ser la primera instrucción del constructor. Si querías validar un argumento antes de pasárselo al padre, tocaba un método estático auxiliar o una expresión retorcida dentro de la llamada. Ahora:

public class Precio extends Importe {

    public Precio(BigDecimal valor) {
        if (valor.signum() < 0) {
            throw new IllegalArgumentException("Un precio no puede ser negativo");
        }
        super(valor);
    }
}

La regla es sencilla: antes de super(...) puedes ejecutar código y asignar campos de tu clase, pero no leer this ni llamar a sus métodos. Es un cambio pequeño que elimina un patrón feo muy extendido en jerarquías de dominio.

Scoped Values: el sustituto de ThreadLocal (JEP 506)

ThreadLocal es la forma clásica de pasar contexto (usuario, tenant, id de traza) sin arrastrarlo por todos los métodos. Tiene tres problemas conocidos: es mutable, hay que acordarse de limpiarlo y, con millones de hilos virtuales, cada copia cuesta memoria.

private static final ScopedValue<String> TENANT = ScopedValue.newInstance();

void atender(Peticion peticion) {
    ScopedValue.where(TENANT, peticion.tenant())
               .run(() -> servicio.procesar(peticion));
}

// En cualquier punto de la cadena de llamadas:
String tenant = TENANT.get();

El valor existe solo durante la ejecución de ese bloque, es inmutable y se libera solo al salir. No hay remove() que olvidar. Después de cuatro previews, en Java 25 es definitivo.

Las novedades que cambian cómo corre tu aplicación

Aquí no cambias código: cambias flags de arranque y, a veces, la factura del cloud.

Cabeceras de objeto compactas (JEP 519)

Cada objeto Java lleva una cabecera. En una JVM de 64 bits con punteros de clase comprimidos ocupa 12 bytes. Con cabeceras compactas pasa a 8. En aplicaciones con muchos objetos pequeños —entidades, DTOs, colecciones— eso se nota en el heap y en la presión del recolector.

En Java 24 era experimental; en Java 25 es una opción de producto, pero no viene activada por defecto:

java -XX:+UseCompactObjectHeaders -jar app.jar

Es de los cambios con mejor relación esfuerzo/beneficio del salto a 25: un flag, sin tocar código. Mídelo con tu carga real antes de darlo por bueno, como cualquier ajuste de JVM.

Caché AOT: arrancar más rápido (JEP 514 y 515)

Java 24 introdujo una caché ahead-of-time de clases cargadas y enlazadas. Java 25 la simplifica (un solo paso para generarla) y le añade los perfiles de métodos, para que el JIT no tenga que volver a aprender desde cero en cada arranque:

# Ejecución de entrenamiento: genera la caché
java -XX:AOTCacheOutput=app.aot -jar app.jar

# Arranques posteriores: la usan
java -XX:AOTCache=app.aot -jar app.jar

Donde más rinde es en contenedores que escalan a menudo y en servicios con arranque lento por culpa de frameworks que escanean mucho classpath. Encaja bien en una imagen Docker: la caché se genera en el build y viaja con la aplicación.

Recolectores y observabilidad

  • Shenandoah generacional (JEP 521) pasa a ser de producto: ya no hace falta desbloquear opciones experimentales.
  • JFR gana perfilado por tiempo de CPU (JEP 509, experimental en Linux), muestreo cooperativo más estable (JEP 518) y medición de tiempos por método sin tocar código (JEP 520). Para diagnosticar en producción, Flight Recorder es cada vez más la primera herramienta y no la última.

Seguridad

La API de derivación de claves (JEP 510) es definitiva: HKDF y compañía con una API estándar, sin librerías externas. Y la codificación PEM de claves y certificados (JEP 470) llega en preview: leer y escribir un .pem sin pelearse con Base64 a mano, algo que se pedía desde hace años.

Lo que sigue en preview o incubadora

No son para producción todavía, pero marcan hacia dónde va el lenguaje:

  • Structured Concurrency (quinta preview): tratar un grupo de tareas concurrentes como una unidad, con cancelación y errores coherentes.
  • Stable Values (preview): valores que se inicializan una sola vez, de forma perezosa y segura entre hilos, y que la JVM puede tratar como constantes.
  • Tipos primitivos en patrones (tercera preview): switch e instanceof sobre int, double y compañía.
  • Vector API (décima incubadora): operaciones SIMD desde Java.

Y una eliminación: desaparece el port de 32 bits para x86 (JEP 503). Si todavía tienes algo corriendo en una JVM de 32 bits, este es el aviso.

Java 25 vs Java 21: lo que ganas por el camino

Esta es la parte que se olvida. Quien migra de 21 a 25 recibe también todo lo que se cerró en 22, 23 y 24. Lo más relevante:

NovedadVersiónQué te da
Hilos virtuales sin pinning en synchronized (JEP 491)24Los hilos virtuales ya no bloquean su hilo portador dentro de synchronized. Es el cambio para quien usa hilos virtuales con librerías antiguas
Stream Gatherers (JEP 485)24Operaciones intermedias propias en streams: ventanas, lotes, escaneos
Variables y patrones sin nombre (JEP 456)22_ para lo que no usas: catch (Exception _), (_, v) -> …
Foreign Function & Memory API (JEP 454)22Llamar a código nativo y gestionar memoria fuera del heap sin JNI
Programas de varios ficheros sin compilar (JEP 458)22java Main.java compila y ejecuta también los ficheros que usa
Comentarios de documentación en Markdown (JEP 467)23Javadoc escrito en Markdown con ///
ZGC generacional por defecto (JEP 474)23El modo generacional pasa a ser el normal; en 24 se elimina el otro
Class-File API (JEP 484)24API estándar para leer y generar bytecode; las herramientas dependerán menos de ASM
Criptografía post-cuántica ML-KEM y ML-DSA (JEP 496 y 497)24Algoritmos resistentes a ordenadores cuánticos en la plataforma estándar

Dos de ellas merecen un ejemplo.

Stream Gatherers resuelven algo que antes obligaba a salir del stream o a escribir un Collector retorcido. Procesar en lotes de tres:

List<List<Integer>> lotes = Stream.of(1, 2, 3, 4, 5, 6, 7)
        .gather(Gatherers.windowFixed(3))
        .toList();
// [[1, 2, 3], [4, 5, 6], [7]]

El fin del pinning es menos vistoso y más importante. En Java 21, un hilo virtual que entraba en un bloque synchronized y se quedaba esperando (una llamada a base de datos, por ejemplo) inmovilizaba el hilo del sistema operativo que lo transportaba. Con muchos a la vez, el servicio podía quedarse sin portadores y colgarse aunque la CPU estuviera ociosa. La solución en 21 era revisar dependencias y cambiar synchronized por ReentrantLock. Desde Java 24 ya no hace falta: si usas hilos virtuales, Java 25 es donde de verdad se vuelven seguros de usar a gran escala.

Qué se rompe al migrar de Java 21 a Java 25

Pocas cosas, pero conviene saberlas antes:

  • El Security Manager queda desactivado de forma permanente (JEP 486). Si alguna librería o servidor de aplicaciones antiguo lo usa, falla al arrancar. Es más habitual en software de hace diez años que en aplicaciones Spring modernas.
  • ZGC ya no tiene modo no generacional (JEP 490). Si arrancas con -XX:+UseZGC -XX:-ZGenerational, revisa los flags.
  • sun.misc.Unsafe avisa cuando se usan sus métodos de acceso a memoria (JEP 498). No rompe, pero ensucia los logs y anuncia que en una versión futura dejará de funcionar. Suele venir de dependencias, no de tu código: actualízalas.
  • JNI empieza a restringirse (JEP 472): el uso de código nativo genera avisos si no se habilita explícitamente con --enable-native-access.
  • Las String Templates desaparecieron. Estuvieron en preview en 21 y 22 y se retiraron en 23 para rediseñarlas. Solo te afecta si las usabas con --enable-preview, cosa que en producción no debería haber pasado.
  • Versión de fichero de clase 69. Toda herramienta que manipula bytecode —Lombok, Mockito, Byte Buddy, Jacoco, agentes de APM— tiene que conocer esa versión. Este es el fallo más frecuente en la primera compilación, y se arregla subiendo versiones de plugins y dependencias.

¿Es necesario actualizar Java? La fecha que importa es octubre de 2026

La respuesta corta: depende de qué JDK tengas instalado, y mucha gente no lo sabe con certeza.

Si usas Oracle JDK 21 bajo la licencia gratuita (NFTC), Oracle lo dice sin rodeos: el lanzamiento de Java 25 abrió un año de solapamiento para pasar de 21 a 25, y las actualizaciones de Oracle JDK 21 a partir del parche de octubre de 2026 pasan a la licencia OTN, que no permite uso gratuito en producción. Quedarte en 21 con Oracle JDK tiene, desde ese mes, un coste de licencia o un coste de seguridad por no parchear. Oracle JDK 25 sí es gratuito.

Si usas una distribución OpenJDK —Eclipse Temurin, Amazon Corretto, Microsoft Build of OpenJDK, Azul Zulu, la que viene en tu imagen base de Docker—, Java 21 sigue recibiendo parches según el calendario de cada proveedor. No hay urgencia de licencia; la migración a 25 se planifica por lo que aporta, no por obligación.

Cómo saber cuál tienes, en diez segundos:

java -version

La línea del runtime dice el proveedor. Si pone Java(TM) SE Runtime Environment de Oracle, estás en el primer caso. Y revisa también las imágenes Docker de tus servicios: el JDK de producción no siempre es el mismo que el del portátil de quien desarrolla.

Hoja de ruta: migrar de Java 21 a Java 25 sin sustos

El salto 21 → 25 es de los más tranquilos que ha habido entre LTS. Aun así, conviene hacerlo en orden:

  1. Inventario. Qué JDK corre en cada servicio, en cada imagen y en cada pipeline de CI. Suele haber sorpresas: un job antiguo que compila con 17, un contenedor con 11.

  2. Compilar con 25 sin cambiar nada. En Maven basta con la propiedad de versión; en Gradle, la toolchain a 25. Los errores de esta fase son casi siempre de plugins y herramientas de bytecode que no conocen la versión 69. Se arreglan subiendo versiones.

    <properties>
        <maven.compiler.release>25</maven.compiler.release>
    </properties>
  3. Ejecutar la batería de tests completa y leer los avisos nuevos: Unsafe, acceso nativo, APIs obsoletas. jdeps --jdk-internals te dice qué dependencias tocan APIs internas del JDK.

  4. Desplegar en un entorno previo con la misma carga que producción y comparar memoria, latencias y tiempos de arranque con la versión anterior. Es el momento de probar -XX:+UseCompactObjectHeaders y la caché AOT, de uno en uno, para saber qué ha causado cada cambio.

  5. Producción de forma gradual: un servicio o una réplica primero, el resto después.

  6. Solo entonces, adoptar las novedades del lenguaje: Scoped Values donde haya ThreadLocal, Gatherers donde haya bucles que salían del stream, validación en constructores. Mezclar el cambio de versión con refactorizaciones hace imposible saber qué ha roto qué.

Si trabajas con Spring Boot

Spring Boot 4 exige como mínimo Java 17 y funciona sobre Java 25, que es donde mejor rinden los hilos virtuales gracias al fin del pinning. Si todavía estás en Spring Boot 3, lo razonable es separar los dos saltos: primero el JDK, luego el framework, o al revés, pero no los dos en el mismo despliegue. Todo el detalle de la migración del framework está en Spring Boot 4: novedades y migración desde Spring Boot 3.

Y si tu equipo ya domina lo básico y quiere ir más allá —arquitectura hexagonal, mensajería, microservicios, operación en Kubernetes—, eso es lo que cubre Spring Boot Avanzado.

Si estás aprendiendo Java: por dónde empezar

Una pregunta que aparece mucho al ver tantas versiones: ¿aprendo con la última? La respuesta es que los fundamentos de Java moderno no han cambiado entre 21 y 25. Records, clases selladas, pattern matching, switch como expresión, text blocks, streams, Optional: todo eso es lo que hay que dominar, y está igual en 25. Lo nuevo de Java 25 se construye encima.

Es el enfoque de la Guía Javañol, el manual de Java en español que escribí y que se usa como material docente en la UIB: cubre Java 17–21, orientación a objetos, streams, Maven y las novedades modernas del lenguaje, con el orden pensado para aprender sin arrastrar hábitos de Java 8. Con esa base, las novedades de Java 25 de este artículo se leen como lo que son: mejoras sobre algo que ya entiendes.

En resumen

  • Java 25 es la LTS actual y la referencia para producción hasta 2030 en soporte Premier de Oracle. Java 27 es más reciente, pero no es LTS.
  • Lo que más aporta para código: Scoped Values, constructores con validación previa, main sin ceremonia y, heredado de 22–24, Stream Gatherers y _.
  • Lo que más aporta en ejecución: hilos virtuales sin pinning, cabeceras compactas y caché AOT.
  • Lo que se rompe es poco y conocido: Security Manager, ZGC no generacional, herramientas de bytecode antiguas.
  • Si usas Oracle JDK 21 con licencia gratuita, octubre de 2026 es tu fecha límite. Si usas OpenJDK, tienes margen para hacerlo bien.

Si tu organización tiene varios servicios Java que mover y quiere un plan antes de tocar producción, es el tipo de trabajo que hago como consultor IT: inventario, orden de migración y verificación con carga real.

¿Buscas un consultor IT para tu empresa? Conoce mis servicios de consultoría IT: arquitectura cloud, desarrollo fullstack y liderazgo técnico. ¿Empresa en Mallorca o Baleares? Consultor IT en Mallorca.

¿Listo para transformar tu stack tecnológico?

Hablemos sobre cómo llevar tus sistemas al siguiente nivel, optimizar el rendimiento y potenciar el talento de tu equipo.

O cuéntame por escrito

Protegido por reCAPTCHA. Tus datos solo se usan para responderte — ver la política de privacidad.