Java no muere, renace
\nCada año alguien escribe «Java está muerto». Y cada año Java demuestra lo contrario. En 2025, el lenguaje que ya tiene casi 30 años recibe varias actualizaciones fundamentales. Si escribes en Java, pero la última vez que viste el changelog fue hace un año, ya estás atrasado. Analicemos qué cambiará concretamente y cómo afectarán estos cambios a tu código.
\nNo te abrumaré con especificaciones técnicas. En su lugar, te mostraré ejemplos reales que podrás ejecutar hoy mismo (bueno, casi). ¡Allá vamos!
\n\nHilos virtuales (Project Loom) — el fin de la era de los bloqueos
\nEste es, quizás, el cambio más sonado. Los hilos virtuales (virtual threads) son hilos ligeros que permiten escribir código asíncrono con un estilo síncrono. En 2025, por fin se vuelven estables y recomendados para producción.
\nAntes escribías algo como:
\nExecutorService executor = Executors.newFixedThreadPool(10);\nexecutor.submit(() -> {\n // llamada bloqueante\n String result = restTemplate.getForObject(url, String.class);\n return result;\n});\nEl problema es que cada hilo es un objeto pesado. 10 hilos está bien, 10 000 ya es un problema. Con los hilos virtuales puedes ejecutar millones de hilos sin preocuparte por la memoria:
\ntry (var executor = Executors.newVirtualThreadPerTaskExecutor()) {\n for (int i = 0; i < 100_000; i++) {\n executor.submit(() -> {\n // ahora esto es ligero\n String result = restTemplate.getForObject(url, String.class);\n return result;\n });\n }\n}\nLa diferencia clave: los hilos virtuales no están vinculados a los hilos del SO. Cuando un hilo se bloquea (por ejemplo, en I/O), la JVM simplemente lo cambia a otro hilo virtual. Sin sobrecarga adicional.
\n¿Qué significa esto para ti? Olvídate de frameworks asíncronos complejos como CompletableFuture y bibliotecas reactivas. En 2025, el código síncrono estándar con hilos virtuales será más rápido y más sencillo.
\n\nCómo migrar
\nReemplaza newFixedThreadPool por newVirtualThreadPerTaskExecutor. Si usas Spring Boot, actualiza a la versión 3.2+, que ya tiene soporte. Solo asegúrate de que tus bibliotecas no usen synchronized en secciones críticas: es el único punto donde los hilos virtuales podrían «atascarse».
Pattern Matching y Switch — el código se vuelve más corto
\nEn 2025, el pattern matching ha llegado a switch y instanceof. Ahora, en lugar de montones de if-else anidados, puedes escribir de forma concisa y legible.
Antes (estilo antiguo):
\nif (obj instanceof String) {\n String s = (String) obj;\n System.out.println(s.length());\n} else if (obj instanceof Integer) {\n Integer i = (Integer) obj;\n System.out.println(i * 2);\n}\nAhora (Java 21+):
\nswitch (obj) {\n case String s -> System.out.println(s.length());\n case Integer i -> System.out.println(i * 2);\n case null -> System.out.println("null");\n default -> System.out.println("unknown");\n}\nObserva el case null: es una mejora aparte. Antes, switch lanzaba una NullPointerException al pasar null. Ahora puedes manejarlo explícitamente.
Otra característica genial son los record patterns. Si tienes un record:
\nrecord Point(int x, int y) {}\nPuedes escribir:
\nif (obj instanceof Point(int x, int y)) {\n System.out.println("x=" + x + ", y=" + y);\n}\nSin conversiones de tipo innecesarias. En 2025, esto será mainstream: úsalo para que tu código sea más limpio.
\n\nRecolección de basura: ZGC y Generational GC
\nEn 2025, la recolección de basura se ha vuelto aún más rápida. ZGC (Z Garbage Collector) ahora está habilitado por defecto para la mayoría de las aplicaciones. Su