Java Toolbox: Java 25 (LTS)

Tabla de Contenidos
- Introducción
- Estados de los JEPs
- Características Finalizadas
- Características en Preview
- Características Experimentales
- Características en Incubación
- Conclusión
Introducción
El 16 de septiembre de 2025, Oracle lanzó Java 25, la nueva versión LTS (Long-Term Support) que incluye 18 JEPs (Java Enhancement Proposals) enfocados en mejorar el lenguaje, las APIs estándar y el rendimiento del runtime.
Esta versión representa un salto significativo desde Java 21 LTS, consolidando años de experimentación en áreas críticas:
- 7 características finalizadas que evolucionaron desde incubación y preview
- Mejoras de performance y runtime bajo los auspicios de Project Leyden y HotSpot JVM
- Nuevas APIs para concurrencia, criptografía y simplificación del lenguaje
Oracle proporcionará soporte extendido para Java 25 por al menos 8 años, convirtiéndola en una base sólida para proyectos de producción.
Java 25 LTS es la primera versión LTS desde Java 21 (septiembre 2023), con miles de mejoras que aumentan la productividad del desarrollador y mejoran el rendimiento, estabilidad y seguridad de la plataforma.
Estados de los JEPs
Antes de explorar las características, es importante entender los diferentes estados en los que puede encontrarse un JEP (Java Enhancement Proposal):
Incubator (Incubación)
¿Qué es? Una API o módulo experimental que se incluye en el JDK pero no forma parte de la especificación Java SE.
Características:
- Requiere flags especiales para ser usado:
--add-modules jdk.incubator.<nombre> - Puede cambiar significativamente entre versiones
- No hay garantía de estabilidad
- Ideal para experimentación y feedback temprano
Ejemplo:
# Usar módulo incubator
javac --add-modules jdk.incubator.vector MyClass.java
java --add-modules jdk.incubator.vector MyApp
Advertencia: Las APIs en incubación pueden cambiar o eliminarse sin previo aviso. No usar en producción.
Preview (Vista previa)
¿Qué es? Una característica del lenguaje o API estándar que está completamente especificada pero aún no es definitiva.
Características:
- Requiere el flag
--enable-previewpara compilar y ejecutar - Puede sufrir cambios menores basados en feedback de la comunidad
- Forma parte de la especificación Java SE
- Más estable que incubator, pero no definitiva
Ejemplo:
# Usar características en preview
javac --enable-preview --release 25 MyClass.java
java --enable-preview MyApp
Progresión típica:
- Primera Preview → 2. Segunda Preview → 3. Tercera Preview → 4. Finalizada
Cada iteración de preview incorpora mejoras basadas en el uso real por la comunidad.
Experimental
¿Qué es? Una característica de JVM o GC que está disponible pero requiere activación explícita mediante flags.
Características:
- Generalmente relacionada con rendimiento o runtime
- Puede tener overhead o comportamiento inesperado
- Requiere flags JVM específicos (ej:
-XX:+UnlockExperimentalVMOptions) - Se usa para validar conceptos antes de convertirlos en estándar
Ejemplo:
# Activar característica experimental
java -XX:+UnlockExperimentalVMOptions -XX:+UseNewFeature MyApp
Final (Finalizada)
¿Qué es? Una característica completamente estable y parte permanente de la plataforma Java.
Características:
- No requiere flags especiales
- Garantía de estabilidad y compatibilidad hacia atrás
- Especificación completa y documentada
- Lista para producción
Producción: Las características finalizadas son seguras para usar en aplicaciones de producción y cuentan con soporte completo.
Ciclo de vida típico de un JEP
┌─────────────┐
│ Incubator │ (1-3 versiones)
└──────┬──────┘
│
▼
┌─────────────┐
│ Preview │ (1-4 versiones)
│ Primera → │
│ Segunda → │
│ Tercera │
└──────┬──────┘
│
▼
┌─────────────┐
│ Final │ (Permanente)
└─────────────┘
Distribución en Java 25
| Estado | Cantidad | Requiere flags | Producción |
|---|---|---|---|
| Finalizada | 7 JEPs | ❌ No | ✅ Sí |
| Preview | 3 JEPs | ✅ --enable-preview |
⚠️ No recomendado |
| Experimental | 1 JEP | ✅ Flags JVM | ⚠️ No recomendado |
| Incubator | 1 JEP | ✅ --add-modules |
❌ No |
Recomendaciones
Para producción:
- ✅ Usar solo características finalizadas
- ✅ Mantenerse actualizado con la documentación oficial
- ✅ Probar exhaustivamente antes de migrar
Para desarrollo/experimentación:
- ⚠️ Las características en preview son relativamente estables
- ⚠️ Las características experimentales pueden afectar el rendimiento
- ❌ Evitar incubator a menos que sea para aprendizaje/feedback
Características Finalizadas
Las siguientes características están completamente estables y listas para usar en producción. No requieren flags especiales.
Scoped Values (JEP 506)
¿Qué es?
Scoped Values (JEP 506) es una alternativa moderna a ThreadLocal diseñada específicamente para compartir datos inmutables entre componentes de una aplicación sin pasarlos explícitamente como parámetros.
Estado: FINALIZADA - Pasó por incubación (JDK 20) y varias iteraciones de preview (JDK 21-24) antes de finalizarse en Java 25.
El problema con ThreadLocal
ThreadLocal ha sido útil pero tiene limitaciones importantes:
// ThreadLocal - puede causar memory leaks
private static final ThreadLocal<User> CURRENT_USER = new ThreadLocal<>();
public void processRequest(Request request) {
try {
CURRENT_USER.set(authenticate(request));
// ... procesar request
} finally {
CURRENT_USER.remove(); // Fácil olvidar esto = memory leak
}
}
Problemas de ThreadLocal:
- Mutable: Los valores pueden cambiar, causando efectos secundarios
- Memory leaks: Olvidar
remove()causa fugas de memoria - Mal rendimiento con Virtual Threads: Diseñado para threads del sistema operativo
Solución con Scoped Values
// Java 25 - Scoped Values
import java.lang.ScopedValue;
private static final ScopedValue<User> CURRENT_USER = ScopedValue.newInstance();
public void processRequest(Request request) {
User user = authenticate(request);
// El valor existe solo dentro de este scope
ScopedValue.where(CURRENT_USER, user)
.run(() -> {
processBusinessLogic();
// Automáticamente se limpia al salir
});
}
private void processBusinessLogic() {
User user = CURRENT_USER.get(); // Acceso inmutable
System.out.println("Procesando para: " + user.getName());
}
Uso con Virtual Threads
import java.lang.ScopedValue;
import java.util.concurrent.Executors;
public class ScopedValueExample {
static final ScopedValue<String> USER = ScopedValue.newInstance();
public static void main(String[] args) throws InterruptedException {
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
executor.submit(() ->
ScopedValue.where(USER, "Alice").run(() -> {
System.out.println("Thread: " + Thread.currentThread());
System.out.println("User: " + USER.get());
})
);
executor.submit(() ->
ScopedValue.where(USER, "Bob").run(() -> {
System.out.println("Thread: " + Thread.currentThread());
System.out.println("User: " + USER.get());
})
);
Thread.sleep(200); // Esperar a que terminen
}
}
}
Ventajas
- Inmutabilidad: Los valores no pueden cambiar dentro del scope
- Sin memory leaks: Limpieza automática al salir del scope
- Performance: Más eficiente que ThreadLocal, especialmente con Virtual Threads
- Seguridad: Valores compartidos de forma segura entre threads
Cambio en Java 25
Cambio de la versión final: El método ScopedValue.orElse() ya no acepta null como argumento.
Casos de uso
- Contextos de seguridad: Usuario autenticado, permisos, roles
- Request IDs: Trazabilidad en logs distribuidos
- Configuración por request: Locale, timezone, tenant ID
- Transacciones: Estado transaccional sin propagación manual
Flexible Constructor Bodies (JEP 513)
¿Qué es?
Flexible Constructor Bodies (JEP 513) permite escribir código antes de llamar a super() o this(), eliminando una restricción histórica de Java.
Estado: FINALIZADA - Estuvo en preview en JDK 22-24 y se finaliza en Java 25.
El problema anterior
Antes de Java 25, super() o this() debían ser la primera línea en un constructor:
// Antes de Java 25 - NO compilaba
public class UserAccount {
private final String username;
private final String normalizedEmail;
public UserAccount(String username, String email) {
// Error: debe llamar a super() o this() primero
String cleaned = email.trim().toLowerCase();
super(); // Debe ser la primera línea
this.username = username;
this.normalizedEmail = cleaned;
}
}
Solución en Java 25
// Java 25 - Código antes de super()
public class Employee extends Person {
final String name;
final int age;
Employee(String name, int age) {
// ¡Ahora podemos validar ANTES de llamar a super()!
if (age < 18 || age > 67) {
throw new IllegalArgumentException("Age must be between 18 and 67");
}
super(age); // Ya no necesita ser la primera línea
this.name = name;
}
}
Ejemplo con inicialización compleja
public class ComplexObject extends BaseObject {
private final Configuration config;
public ComplexObject(Map<String, Object> rawConfig) {
// Validación y transformación antes de super()
if (rawConfig == null || rawConfig.isEmpty()) {
throw new IllegalArgumentException("Config cannot be empty");
}
// Procesar configuración
String mode = (String) rawConfig.get("mode");
int timeout = (Integer) rawConfig.getOrDefault("timeout", 5000);
// Crear objeto de configuración
Configuration processedConfig = new Configuration(mode, timeout);
super(processedConfig.getMode()); // Llamada a super con datos procesados
this.config = processedConfig;
}
}
Ventajas
- Validación temprana: Verificar argumentos antes de construir el objeto
- Transformaciones locales: Preparar datos sin métodos auxiliares
- Código más legible: Menos indirección y constructores auxiliares
- Fail-fast: Fallar rápidamente antes de incurrir en costos de construcción
Casos de uso
- Validación de argumentos: Rechazar valores inválidos antes de construcción
- Normalización de datos: Limpiar y formatear inputs
- Cálculos preparatorios: Derivar valores antes de asignar campos
- Logging: Registrar intentos de construcción
Instance Main Methods (JEP 512)
¿Qué es?
Compact Source Files and Instance Main Methods (JEP 512) hace que Java sea más accesible para principiantes, permitiendo escribir programas sin boilerplate de clases.
Estado: FINALIZADA - Java ahora soporta archivos compactos y métodos main de instancia.
El problema anterior
// Antes: Hello World tradicional
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
Solución en Java 25
// Java 25 - Compact Source File
void main() {
IO.println("Hello, World!");
}
Nueva clase java.lang.IO
Java 25 introduce java.lang.IO para simplificar entrada/salida:
void main() {
// Salida
IO.println("¿Cuál es tu nombre?");
IO.print(">>> ");
// Entrada
String name = IO.readln();
IO.println("¡Hola, " + name + "!");
}
Métodos disponibles:
IO.println(Object o)- Imprimir con salto de líneaIO.println()- Salto de líneaIO.print(Object o)- Imprimir sin salto de líneaIO.readln()- Leer líneaIO.readln(String prompt)- Leer línea con prompt
Imports automáticos
Todas las clases públicas de java.base se importan automáticamente:
void main() {
// No necesitamos importar List, ArrayList, etc.
List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
IO.println("Names: " + names);
}
Instance main methods
El método main ahora puede ser de instancia (no estático):
// Main de instancia
class Calculator {
private int result = 0;
void main() {
add(10);
multiply(5);
IO.println("Result: " + result);
}
void add(int value) {
result += value;
}
void multiply(int value) {
result *= value;
}
}
Ventajas
- Aprendizaje simplificado: Ideal para enseñar programación
- Scripting rápido: Escribir scripts sin boilerplate
- Prototipos ágiles: Desarrollo rápido de demos
- Menor barrera de entrada: Java más accesible para principiantes
Compact Object Headers (JEP 519)
¿Qué es?
Compact Object Headers (JEP 519) reduce el tamaño de los headers de objetos en arquitecturas de 64 bits, mejorando significativamente el uso de memoria.
Estado: FINALIZADA - Experimental en JDK 24, estable en Java 25.
El problema anterior
En JVM de 64 bits, cada objeto tiene un header que ocupa espacio:
- Con compressed oops: 12 bytes
- Sin compressed oops: 16 bytes
Para aplicaciones con millones de objetos, esto representa un overhead significativo.
Solución en Java 25
Java 25 reduce el tamaño del header de objeto a 8 bytes en ambos casos:
- Reducción con compressed oops: 33%
- Reducción sin compressed oops: 50%
Beneficios medidos
Según benchmarks oficiales (SPECjbb2015):
- Heap usage: Reducción del 22%
- CPU usage: Reducción del 8%
- GC efficiency: Recolecciones más rápidas
- JSON processing: Hasta 30% más rápido (Amazon)
Cómo habilitar
# Activar Compact Object Headers
java -XX:+UseCompactObjectHeaders MyApp
# Verificar que está activo
java -XX:+UseCompactObjectHeaders -XX:+PrintFlagsFinal MyApp | grep CompactObjectHeaders
Recomendación: Amazon reporta hasta 30% menos CPU en algunos servicios con esta característica activada.
Impacto en aplicaciones reales
Antes (headers tradicionales):
1,000,000 objetos × 12 bytes = 12 MB de overhead
Después (compact headers):
1,000,000 objetos × 8 bytes = 8 MB de overhead
→ Ahorro de 4 MB (33%)
Casos de uso
- Microservicios: Mayor densidad de deployment
- Caching: Más objetos en memoria
- Big Data: Procesamiento de grandes volúmenes
- Cloud: Reducción de costos de memoria
Key Derivation Function API (JEP 510)
¿Qué es?
Key Derivation Function API (JEP 510) introduce una API estándar para funciones de derivación de claves basadas en contraseñas (PBKDF2, scrypt, etc.).
Estado: FINALIZADA - API estándar para KDF en Java 25.
El problema anterior
Derivar claves de contraseñas requería uso de APIs de bajo nivel:
// Código complejo y propenso a errores
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
char[] password = "hunter2".toCharArray();
byte[] salt = generateSalt();
int iterations = 65536;
int keyLength = 256;
PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, keyLength);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
SecretKey key = factory.generateSecret(spec);
Solución en Java 25
// Java 25 - API simplificada
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
public class KeyDerivationExample {
public static void main(String[] args) throws Exception {
char[] password = "hunter2".toCharArray();
byte[] salt = "somesalt".getBytes();
// Usar API estándar
PBEKeySpec spec = new PBEKeySpec(password, salt, 65536, 256);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
SecretKey key = factory.generateSecret(spec);
System.out.println("Derived key format: " + key.getFormat());
System.out.println("Key length: " + key.getEncoded().length);
}
}
Ventajas
- API estandarizada: No más dependencias externas
- Seguridad mejorada: Implementaciones verificadas
- Flexibilidad: Soporte para múltiples algoritmos (PBKDF2, scrypt)
- Facilidad de uso: API más intuitiva
Casos de uso
- Autenticación: Hash seguro de contraseñas
- Cifrado: Derivar claves de encryption desde passwords
- Key stretching: Aumentar seguridad de claves débiles
- Password storage: Almacenamiento seguro de credenciales
Ahead-of-Time Method Profiling (JEP 515)
¿Qué es?
Ahead-of-Time Method Profiling (JEP 515) permite crear perfiles de ejecución reutilizables para acelerar el warm-up de aplicaciones Java.
Estado: FINALIZADA - Parte de Project Leyden, disponible en Java 25.
El problema anterior
Cuando una aplicación Java inicia, el JVM debe:
- Recopilar estadísticas de métodos
- Identificar hot spots
- Compilar código optimizado con JIT
Esto causa startup lento y warm-up prolongado.
Solución en Java 25
# Paso 1: Grabar perfil de ejecución
java -XX:AOTMode=record -XX:AOTConfiguration=app.aotconf MyApp
# Paso 2: Crear caché AOT desde el perfil
java -XX:AOTMode=create -XX:AOTCache=app.aot -XX:AOTConfiguration=app.aotconf
# Paso 3: Usar caché AOT en ejecución productiva
java -XX:AOTCache=app.aot MyApp
Beneficios medidos
- Warm-up: Reducción del 20% en tiempo de calentamiento
- Peak performance: Alcanzado más rápidamente
- Adaptable: Si el comportamiento cambia, JIT se adapta
- Sin cambios de código: Optimización transparente
Ventajas
- Startup más rápido: Aplicaciones listas más pronto
- Sin cambios de código: Optimización a nivel JVM
- Flexible: Se adapta a cambios en runtime
- Acumulativo: Combina AOT + JIT dinámico
Casos de uso
- Microservicios: Reducir tiempo de inicio en cloud
- Serverless: Mejorar cold starts
- Aplicaciones empresariales: Warm-up más rápido
- CI/CD: Cachés compartidos entre deploys
Generational Shenandoah (JEP 521)
¿Qué es?
Generational Shenandoah (JEP 521) agrega soporte generacional al garbage collector Shenandoah, mejorando throughput y pausas.
Estado: FINALIZADA - Experimental en JDK 24, estable en Java 25.
El problema anterior
Shenandoah GC escaneaba todo el heap en cada ciclo, aunque la mayoría de objetos mueren jóvenes.
Solución en Java 25
Shenandoah ahora maneja generaciones por separado:
- Young generation: Recolectada frecuentemente
- Old generation: Recolectada ocasionalmente
Cómo habilitar
# Activar Generational Shenandoah
java -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational MyApp
Beneficios
- Mejor throughput: Menos tiempo en GC
- Pausas más cortas: Colecciones young rápidas
- Eficiencia: Enfoque en objetos que mueren rápido
- Alineación con G1/ZGC: Características similares
Casos de uso
- Aplicaciones de baja latencia: Pausas predecibles
- Grandes heaps: Manejo eficiente de memoria
- Microservicios: GC con overhead mínimo
Características en Preview
Las siguientes características requieren --enable-preview para compilar y ejecutar. No se recomiendan para producción hasta que sean finalizadas.
Module Import Declarations (JEP 511)
¿Qué es?
Module Import Declarations (JEP 511) simplifica la importación de todas las clases exportadas por un módulo.
Estado: PRIMERA PREVIEW - Requiere --enable-preview
El problema anterior
// Antes de Java 25 - imports individuales
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.HashSet;
import java.util.stream.Collectors;
import java.util.stream.Stream;
// ... muchos más imports
Solución en Java 25
// Java 25 - import de módulo completo
import module java.base;
// Ahora todas las clases públicas del módulo están disponibles
public class DataProcessor {
public Map<String, List<String>> processData(Set<String> input) {
return input.stream()
.collect(Collectors.groupingBy(
s -> s.substring(0, 1),
Collectors.toList()
));
}
}
Reemplazar star imports
// Antes: múltiples star imports
import javax.xml.*;
import javax.xml.parsers.*;
import javax.xml.stream.*;
// Ahora: un solo import de módulo
import module java.xml;
Manejo de ambigüedades
// Problema: ambigüedad con Date
import module java.base; // exporta java.util.Date
import module java.sql; // exporta java.sql.Date
// Solución: import específico
import java.sql.Date;
public class Main {
public static void main(String[] args) {
Date d = Date.valueOf("2025-06-15");
System.out.println("Date: " + d);
}
}
Cómo habilitar
# Compilar
javac --enable-preview --release 25 MyClass.java
# Ejecutar
java --enable-preview MyApp
Ventajas
- Menos verbosidad: Menos líneas de imports
- Mejor mantenibilidad: No necesitas actualizar imports
- Claridad modular: Dependencias explícitas de módulos
Primitive Types in Patterns (JEP 507)
¿Qué es?
Primitive Types in Patterns (JEP 507) extiende el pattern matching para soportar tipos primitivos.
Estado: TERCERA PREVIEW - Requiere --enable-preview
El problema anterior
// Antes - boxing necesario
Object value = 42; // int autoboxeado a Integer
switch (value) {
case Integer i when i > 0 -> System.out.println("Positivo: " + i);
case Integer i when i < 0 -> System.out.println("Negativo: " + i);
case Integer i -> System.out.println("Cero");
default -> System.out.println("No es Integer");
}
Solución en Java 25
// Java 25 - pattern matching con primitivos
Object value = 42;
switch (value) {
case int i when i > 0 -> System.out.println("Positivo: " + i);
case int i when i < 0 -> System.out.println("Negativo: " + i);
case int i -> System.out.println("Cero");
case long l -> System.out.println("Long: " + l);
case double d -> System.out.println("Double: " + d);
default -> System.out.println("Otro tipo");
}
Pattern matching con instanceof
// También funciona con instanceof
if (obj instanceof int i) {
System.out.println("Es un int: " + i);
}
// Identificar tipo dinámicamente
public static String identifyType(Object value) {
return switch (value) {
case int i -> String.format("int: %d", i);
case Double d -> String.format("Double: %f", d);
case String s -> String.format("String: %s", s);
default -> "Unknown type";
};
}
Cómo habilitar
# Compilar y ejecutar
javac --enable-preview --release 25 MyClass.java
java --enable-preview MyApp
Ventajas
- Sin boxing overhead: Mejor rendimiento
- Código más expresivo: Patrones directos con primitivos
- Type safety: El compilador valida conversiones
Structured Concurrency (JEP 505)
¿Qué es?
Structured Concurrency (JEP 505) trata múltiples tareas concurrentes como una única unidad de trabajo.
Estado: QUINTA PREVIEW - Requiere --enable-preview. Se espera finalización en Java 26.
El problema anterior
// Enfoque tradicional - complejo
ExecutorService executor = Executors.newCachedThreadPool();
try {
Future<User> userFuture = executor.submit(() -> fetchUser(userId));
Future<Orders> ordersFuture = executor.submit(() -> fetchOrders(userId));
User user = userFuture.get();
Orders orders = ordersFuture.get();
return new UserProfile(user, orders);
} catch (InterruptedException | ExecutionException e) {
// ¿Qué pasa con las tareas en curso?
throw new RuntimeException(e);
} finally {
executor.shutdown();
}
Solución en Java 25
// Java 25 - Structured Concurrency
import java.util.concurrent.StructuredTaskScope;
try (var scope = StructuredTaskScope.<String>open()) {
var userTask = scope.fork(() -> fetchUser(userId));
var ordersTask = scope.fork(() -> fetchOrders(userId));
scope.join(); // Esperar a que todas terminen
String user = userTask.get();
String orders = ordersTask.get();
System.out.println("Usuario: " + user);
System.out.println("Pedidos: " + orders);
}
Shutdown on failure
// Cancelar todas si una falla
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
var task1 = scope.fork(() -> fetchDataFromService1());
var task2 = scope.fork(() -> fetchDataFromService2());
scope.join();
scope.throwIfFailed(); // Propagar excepciones
String result1 = task1.resultNow();
String result2 = task2.resultNow();
} catch (InterruptedException | ExecutionException e) {
System.err.println("Error: " + e.getMessage());
}
Cambios en Java 25
La quinta preview introduce:
- Métodos factory estáticos:
StructuredTaskScope.open() - Mayor flexibilidad: Mejores políticas de join y manejo de errores
- API más consistente: Sintaxis más clara
Cómo habilitar
# Compilar y ejecutar
javac --enable-preview --release 25 App.java
java --enable-preview App
Ventajas
- Cancelación automática: Si una falla, todas se cancelan
- Gestión de ciclo de vida: Limpieza automática
- Código más limpio: Estructura try-with-resources
- Sin thread leaks: Imposible olvidar threads activos
Características Experimentales
Las características experimentales requieren flags JVM específicos. No se recomiendan para producción.
JFR CPU-Time Profiling (JEP 509)
¿Qué es?
JFR CPU-Time Profiling (JEP 509) añade perfilado basado en tiempo de CPU a Java Flight Recorder.
Estado: EXPERIMENTAL - Solo funciona en Linux actualmente.
Problema anterior
Java Flight Recorder (JFR) solo medía el tiempo en “código Java puro”, sin incluir tiempo en código nativo o bibliotecas del sistema.
Solución en Java 25
JFR ahora puede medir:
- Tiempo de CPU real consumido
- Tiempo en código nativo
- Tiempo en bibliotecas del sistema
- Proporciona vista más precisa del uso de CPU
Cómo habilitar
# Grabar con profiling de CPU
java -XX:StartFlightRecording=filename=cpu-time.jfr,duration=10s,settings=profile \
-XX:+UnlockExperimentalVMOptions \
-XX:+JFRCPUProfiling \
MyApp
Análisis
# Analizar el archivo JFR
jcmd <pid> JFR.dump filename=recording.jfr
# O usar JDK Mission Control / VisualVM
Beneficios
- Medición precisa: Incluye todo el tiempo de CPU
- Mejor diagnóstico: Identifica cuellos de botella reales
- Overhead bajo: Diseñado para producción
Casos de uso
- Performance tuning: Identificar métodos costosos
- Análisis de I/O: Ver tiempo real vs tiempo bloqueado
- Optimización: Decisiones basadas en datos precisos
Características en Incubación
Las características en incubación requieren --add-modules y pueden cambiar significativamente. No usar en producción.
Vector API (JEP 508)
¿Qué es?
Vector API (JEP 508) proporciona una API para expresar computaciones vectoriales que se compilan a instrucciones SIMD del hardware.
Estado: DÉCIMA INCUBACIÓN - Requiere --add-modules jdk.incubator.vector
Motivación
Las CPUs modernas tienen instrucciones SIMD (Single Instruction Multiple Data) que pueden procesar múltiples datos simultáneamente, pero Java no las aprovecha fácilmente.
Ejemplo básico
import jdk.incubator.vector.*;
public class VectorExample {
public static void main(String[] args) {
float[] left = {1f, 2f, 3f, 4f};
float[] right = {5f, 6f, 7f, 8f};
// Cargar vectores
FloatVector a = FloatVector.fromArray(FloatVector.SPECIES_128, left, 0);
FloatVector b = FloatVector.fromArray(FloatVector.SPECIES_128, right, 0);
// Sumar vectores (operación paralela)
FloatVector c = a.add(b);
// Extraer resultado
float[] result = new float[FloatVector.SPECIES_128.length()];
c.intoArray(result, 0);
System.out.println("Vector result: " + java.util.Arrays.toString(result));
// Output: [6.0, 8.0, 10.0, 12.0]
}
}
Operaciones soportadas
// Operaciones aritméticas
FloatVector sum = a.add(b);
FloatVector diff = a.sub(b);
FloatVector product = a.mul(b);
FloatVector quotient = a.div(b);
// Operaciones lógicas
IntVector and = intVec1.and(intVec2);
IntVector or = intVec1.or(intVec2);
// Operaciones de comparación
VectorMask<Float> mask = a.compare(VectorOperators.GT, b);
// Operaciones matemáticas
FloatVector sqrt = a.sqrt();
FloatVector abs = a.abs();
Cómo habilitar
# Compilar
javac --add-modules jdk.incubator.vector --enable-preview MyClass.java
# Ejecutar
java --add-modules jdk.incubator.vector --enable-preview MyApp
Ventajas
- Performance: Hasta 4-8x más rápido que código escalar
- Portable: Java se encarga de usar instrucciones SIMD disponibles
- Type-safe: API segura y tipada
- Expresivo: Operaciones vectoriales claras
Casos de uso
- Machine Learning: Operaciones matriciales
- Procesamiento de imágenes: Filtros y transformaciones
- Procesamiento de señales: FFT, convoluciones
- Criptografía: Operaciones paralelas
- Análisis de datos: Agregaciones masivas
Consideraciones
Advertencia: Al estar en incubación, la API puede cambiar. No usar en producción hasta que sea finalizada.
Conclusión
Java 25 LTS representa un salto significativo en la evolución de Java, con mejoras en todos los niveles:
Resumen por estado
✅ Características Finalizadas (7) - Listas para Producción
- Scoped Values (JEP 506): Alternativa moderna a ThreadLocal
- Flexible Constructor Bodies (JEP 513): Validación antes de super()
- Instance Main Methods (JEP 512): Java más simple para principiantes
- Compact Object Headers (JEP 519): 22% menos uso de heap
- Key Derivation Function API (JEP 510): KDF estandarizado
- AOT Method Profiling (JEP 515): 20% mejor warm-up
- Generational Shenandoah (JEP 521): GC más eficiente
⚠️ Características en Preview (3) - Experimentación
- Module Import Declarations (JEP 511): Imports simplificados
- Primitive Types in Patterns (JEP 507): Pattern matching completo
- Structured Concurrency (JEP 505): Concurrencia simplificada
⚠️ Características Experimentales (1)
- JFR CPU-Time Profiling (JEP 509): Profiling preciso de CPU
❌ Características en Incubación (1) - No usar en producción
- Vector API (JEP 508): Computaciones SIMD
Mejoras de rendimiento
| Área | Mejora | JEP |
|---|---|---|
| Heap usage | -22% | 519 |
| CPU usage | -8% a -30% | 519 |
| Warm-up time | -20% | 515 |
| GC efficiency | Mejor throughput | 521 |
Migración a Java 25
Como versión LTS con soporte de 8 años, Java 25 es ideal para proyectos nuevos y migración desde Java 21 LTS o anteriores.
Recomendaciones
Para producción:
- ✅ Usar solo características finalizadas
- ✅ Activar Compact Object Headers para mejor rendimiento
- ✅ Considerar Generational Shenandoah para baja latencia
- ✅ Aprovechar AOT Method Profiling para microservicios
Para experimentación:
- ⚠️ Probar características en preview en entornos de desarrollo
- ⚠️ Dar feedback a OpenJDK sobre características en preview
- ❌ Evitar características en incubación en cualquier ambiente productivo
Fuentes:
- OpenJDK JDK 25
- Java 25, the Next LTS Release - InfoQ
- New Features in Java 25 - Baeldung
- What’s New With Java 25 - JRebel
- Java 25 LTS and IntelliJ IDEA
Última actualización: Febrero 2026
No te olvides de socializar y comptarte!
Share: Facebook LinkedIn