Java sigue avanzando, lanzando novedades en sus distintas versiones. En la versión de Java 24, hemos visto que afianza algunas de las previews que mostraron en versiones anteriores: primitive patterns más potentes y consolidando su apuesta por un código más moderno, claro y potente.

Si vienes de Java 8, 11 o incluso de Java 17, y no has pasado por la 21 aún, es hora de avanzar antes de que sea un gran salto de fe.

Novedades en Java 24

Es importante recordar que algunas implementaciones de las que vamos a hablar están aún en preview. Eso quiere decir que, para que el compilador de Java 24 las entienda, debemos introducir el –enable-preview.

1 Primitive Patterns (preview): los primitivos también existimos (JEP 488)

Java 24 sigue su camino con los primitive patterns y nos entrega una segunda preview (podemos leer las novedades de la primera preview aquí y avanzamos a esta segunda preview), donde amplía las posibilidades del instanceof y switch. Para ello, lo que nos permite es utilizar el pattern matching con los tipos primitivos, int, boolean, double, sin la necesidad de tener que convertirlos en Integer o Double, por ejemplo.

¿Cómo se observa este cambio en código? Antes tendríamos el siguiente código:

Object o = 42;

if (o instanceof Integer i && i > 10) {
    System.out.println("Entero mayor a 10");
}

Ahora, en Java 24 podremos realizar esa comparación directamente con el tipo primitivo:

Object o = 42;

if (o instanceof int i && i > 10) {
    System.out.println("Entero primitivo mayor a 10");
}

2 Stream Gatherers: ¡Streams a mí! JEP 485

JEP 485

Los Streams y Java llevan juntos ya desde Java 8, es por eso que en Java 24 no iba a ser menos. Con la implementación (ya final) de la API de Gatherers, Java 24 nos permite operaciones más avanzadas que las que nos ofrecen los Collectors, como agrupaciones personalizadas, utilización de las ventanas deslizantes, o recolección por lotes(batching). Ilustremos con un ejemplo:

Stream.of(1, 2, 3, 4, 5, 6)
    .gather(Gatherers.windowFixed(3))
    .forEach(System.out::println);
[1, 2, 3], [4, 5, 6]

Se introduce un nuevo método gather que procede de la interfaz de java.util.stream.Gatherer y nos trae una serie de métodos que vamos a poder ir utilizando en futuras implementaciones como operación intermedia dentro del pipeline:

  • windowFixed(int size): agrupa los elementos en ventanas fijas del tamaño size.
  • windowSliding(int size, int step): crea ventanas deslizantes, con peso y tamaños definidos.
  • scan(seed, accumulator): devuelve una secuencia de acumulaciones parciales, algo parecido al reduce pero emitiendo el resultado en cada paso:
import java.util.stream.Stream;
import java.util.stream.Gatherers;

Stream.of(1, 2, 3, 4)
    .gather(Gatherers.scan(0, Integer::sum))
    .forEach(System.out::println);

La salida sería tal que así:

1
3
6
10
  • fold(seed, accumulator, combiner): se encarga de realizar una reducción acumulativa, es decir, como el reduce mencionado anteriormente pero algo más controlado. Un ejemplo:
import java.util.stream.Stream;
import java.util.stream.Gatherers;

Stream.of("Java", "24", "es", "potente")
      .gather(Gatherers.fold(
          "",                              // seed
          (acc, s) -> acc.isEmpty() ? s : acc + " - " + s,  // acumulador
          (a, b) -> a + " - " + b           // combinador para fusión paralela
      ))
      .forEach(System.out::println);

Y la salida sería:

Java - 24 - es - potente

Estos son algunos de los métodos de la librería que consideramos más importantes, pero no son los únicos existentes. Teniendo en cuenta que estamos en versiones preview, es importante que vayamos conociéndolos poco a poco e introduciéndonos en ellos. Es por eso que os invitamos a experimentarlos y echarles un vistazo directamente desde la documentación oficial de Java 24.

4 Scoped Values (preview). Reemplazo moderno para los ThreadLocal. JEP487

JEP 487

Como cuarta preview, Java 24 continúa con los avances en los Scoped Values una nueva forma más segura, inmutable y ligera de pasar datos vía virtual threads.

En versiones anteriores, estos hilos podían ser modificados, es decir, no tenían inmutabilidad, podían existir algunas fugas de memoria y no terminaba de tener un rendimiento óptimo. A continuación, un ejemplo de como era anteriormente y cómo evoluciona:

ThreadLocal<String> userId = new ThreadLocal<>();
userId.set("abc-123");
//Hay que limpiar (remove) manualmente, lo que acaba siendo peligroso

Ahora con Java 24 tendremos lo siguiente:

ScopedValue<String> USER_ID = ScopedValue.newInstance();

ScopedValue.where(USER_ID, "abc-123").run(() -> {
    System.out.println("Usuario actual: " + USER_ID.get());
});

Observamos que ahora el valor será inmutable, lo que nos da una mayor seguridad y está acotado de manera automática, sin tener que recurrir al .remove() que teníamos que utilizar antes para liberar la memoria.

Esta mejora nos podrá servir para pasar información como ID del usuarios, token sessions, configuración de las request, etc, pero recordemos, es una versión preview (recordad: –enable-preview para que nos funcione).

4 Otros cambios: no todo es desarrollar

Java 24 también realiza otros enfoques y novedades, no solo en el estilo de programación. Algunos de los más reseñables son los siguientes:

  • Carga anticipada de las clases. Con el JEP 483 (Ahead-of-Time Class Loading & Linking) se mejora el arranque de la JVM al permitir que la carga y el enlace de clases se realicen antes de la ejecución en lugar de en tiempo de ejecución como era hasta ahora, permitiendo arranques más rápidos, especialmente útil para nuestros microservicios o contenedores con tiempos de respuesta inmediatos.
  • Nueva API oficial (¡final!) para archivos .class. En el JEP 484 se nos da la posibilidad de trabajar con los archivos de clase de manera directa y nativa, directamente desde el JDK sin tener que utilizar herramientas externas como ASM o BCEL. Esto no será especialmente utilizado por los equipos de desarrollo de manera directa, pero es un gran avance que afectará a frameworks como Spring o Hibernate que utilizaban dichas herramientas mencionadas.
  • Virtual Threads without pinning. Con la JEP 491 se propone un nuevo mecanismo para que los virtual threads puedan sincronizarse sin necesidad de pinning (por ejemplo cuando usamos synchronized), es decir, sin tener que anclarse a un hilo de plataforma. Esto permite que las librerías de Java que utilizan el synchronized puedan escalar de manera más eficiente, liberando de manera más eficiente los hilos.

5 Java 24 apuesta por la transformación

Bien es visto que, desde hace ya varias actualizaciones de versión (especialmente desde Java 14), Java está apostando por una forma de programar más declarativa, más segura y más expresiva, llevándolo a un rincón de un lenguaje más moderno, eso sí, sin perder su esencia.

Como perfiles de desarrollo no podemos quejarnos, ya que Java sigue avanzando y adaptándose a las nuevas formas de desarrollar y ha preparado el terreno para Java 25 y posteriores en cuanto a estilo, prácticas limpias y, lo más importante en los tiempos que corren, seguridad en el código. Seguiremos atentos a las nuevas actualizaciones y noticias acerca de Java en sus posteriores versiones. ¿Qué nos deparará el futuro?

Referencias

Cuéntanos qué te parece.

Los comentarios serán moderados. Serán visibles si aportan un argumento constructivo. Si no estás de acuerdo con algún punto, por favor, muestra tus opiniones de manera educada.