Java 22 ya está aquí: novedades del JDK

Está previsto que en marzo de 2024 se publique el JDK 22, la versión número 22 de la plataforma Java, que trae varias novedades interesantes para quienes trabajamos con este lenguaje. Estas mejoras llegan a través de diferentes JEPs, algunos ya estables y listos para usarse sin configuraciones adicionales.

Una de las novedades más prácticas es la posibilidad de ejecutar programas Java que consten de múltiples archivos fuente sin necesidad de compilarlos previamente. Desde hace algunas versiones, ya podíamos ejecutar un archivo .java directamente con el comando java archivo.java, y el sistema se encargaba de compilarlo sobre la marcha. Sin embargo, esto solo funcionaba con un único archivo. Ahora, con Java 22, podemos trabajar con varios archivos .java que contengan distintas clases y ejecutarlos directamente sin crear un proyecto formal ni compilar manualmente.

Por ejemplo, si tenemos una clase principal Main.java y otra clase Emoji.java en archivos separados, podemos ejecutar el programa con un solo comando y el compilador se encargará de compilar ambos archivos automáticamente. Esto facilita mucho hacer pruebas rápidas sin necesidad de configurar un proyecto completo con Maven o Gradle. Además, esta funcionalidad se extiende a la gestión del classpath con el parámetro -cp, lo que permite incluir librerías externas en formato JAR para que el programa las reconozca y utilice sin problemas.

Otra característica que incorpora Java 22 es la introducción de variables y patrones sin nombre. Esto significa que podemos declarar variables que no necesitan un identificador explícito, usando simplemente el guion bajo _ como nombre. Esta funcionalidad es especialmente útil en situaciones donde declaramos variables que no vamos a utilizar, como en bloques try-catch donde capturamos una excepción pero no necesitamos referirnos a ella. En versiones anteriores, el IDE nos advertía sobre variables no usadas, pero ahora podemos indicar explícitamente que la variable es intencionadamente ignorada.

Por ejemplo, en un bloque catch, en lugar de escribir catch (Exception e), podemos usar catch (Exception _) para indicar que no vamos a usar la variable de excepción. Esto hace el código más limpio y evita advertencias innecesarias. Eso sí, no todas las situaciones permiten usar variables sin nombre; por ejemplo, no se puede sustituir el parámetro args del método main por un guion bajo, pero sí en otros contextos donde la variable no se utiliza.

Una de las novedades más potentes y complejas es la nueva API para trabajar con funciones extranjeras, también conocidas como foreign functions. Tradicionalmente, para llamar a código nativo escrito en C o C++ desde Java, se usaba JNI (Java Native Interface), que es potente pero complicado y propenso a errores. Con Java 22, se introduce una API más ergonómica, segura y eficiente para integrar funciones externas.

Esta API permite cargar bibliotecas dinámicas (.dll en Windows, .so en Linux o .dylib en macOS) y buscar funciones por su nombre para invocarlas directamente desde Java. Por ejemplo, si tenemos una biblioteca en C que exporta funciones como sumar, restar y multiplicar, podemos cargar esa biblioteca en Java, obtener un puntero a la función sumar, definir su prototipo (por ejemplo, que recibe dos enteros y devuelve un entero) y luego invocarla con parámetros desde Java.

El proceso implica cargar la biblioteca, buscar la función, definir su firma y finalmente llamar a la función usando el método invoke. Esto permite que la suma se realice en código nativo, con la ventaja de un mejor rendimiento y seguridad en comparación con JNI tradicional.

// Ejemplo simplificado de uso de la nueva API de funciones extranjeras en Java 22

import java.lang.foreign.*;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;

public class Biblioteca {
    public static void main(String[] args) throws Throwable {
        // Cargar la biblioteca dinámica
        System.loadLibrary("funciones"); // funciones.dll, funciones.so o funciones.dylib según SO

        // Obtener el linker del sistema
        Linker linker = Linker.nativeLinker();

        // Buscar la función 'sumar' en la biblioteca
        SymbolLookup lookup = SymbolLookup.loaderLookup();
        MemorySegment sumarFunc = lookup.find("sumar").orElseThrow();

        // Definir el prototipo de la función: int sumar(int, int)
        MethodType mt = MethodType.methodType(int.class, int.class, int.class);
        MethodHandle sumar = linker.downcallHandle(sumarFunc, mt, FunctionDescriptor.of(C_INT, C_INT, C_INT));

        // Invocar la función nativa
        int resultado = (int) sumar.invokeExact(2, 3);
        System.out.println("Resultado de sumar: " + resultado);
    }
}

Además, esta versión mejora el recolector de basura en escenarios donde se usa código nativo, como con JNI. Ahora el recolector puede coordinarse mejor para suspenderse en momentos críticos durante la ejecución de código externo, evitando interferencias que puedan causar problemas de memoria o latencias. Esto debería traducirse en un rendimiento más estable y seguro cuando trabajamos con bibliotecas nativas.

En definitiva, Java 22 trae mejoras que facilitan la ejecución rápida de programas con múltiples archivos, simplifican el manejo de variables no utilizadas y abren la puerta a una integración más segura y eficiente con código nativo externo. Estas novedades amplían las posibilidades para desarrolladores que buscan combinar la robustez de Java con la potencia de otros lenguajes y entornos.

Lista de reproducción
  1. 1
    Java 22 ya está aquí: novedades del JDK
    9 minutos
  2. 2
    Main implícito: Java va a arreglar la forma de escribir el main
    10 minutos
  3. 3
    Java por fin va a tener string interpolations
    10 minutos
  4. 4
    Trabajar con records en Java próximamente va a ser mejor
    9 minutos