Translate

sábado, 2 de mayo de 2026

Records vs Project Valhalla en Java


Java viene evolucionando fuerte en dos direcciones:

  • Java Records → escribir menos código
  • Project Valhalla → ejecutar más rápido


A primera vista parecen competir… pero en realidad se complementan.

  • Usá Records → claridad, simplicidad, APIs
  • Usá Valhalla (Value Types) → rendimiento, memoria
  • Usá ambos → lo ideal en sistemas complejos


Records: el rey de la simplicidad

record User(String name, int age) {}


✔ Inmutables

✔ Menos boilerplate

✔ equals, hashCode, toString automáticos


¿Cuándo usar Records?

DTOs / APIs


record ProductDTO(String name, double price) {}


Perfecto para:

  • REST APIs
  • serialización JSON
  • comunicación entre capas


Modelos simples

record Money(double amount, String currency) {}


Cuando te importa más la legibilidad que el rendimiento


Lógica de negocio

  • servicios
  • respuestas intermedias


El overhead de objetos no suele ser un problema


Limitación clave, un record:

  • vive en el heap
  • tiene identidad
  • usa referencias


Valhalla: el rey del rendimiento

Ejemplo conceptual:


value class Point {

    int x, y;

}



✔ Sin identidad

✔ Sin overhead de objeto

✔ Datos contiguos en memoria


¿Cuándo usar Value Types?

Grandes volúmenes de datos


value class Point {

    int x, y;

}


List<Point>


Mucho más eficiente que objetos tradicionales


Simulaciones

  • físicas
  • partículas
  • coordenadas


Miles o millones de instancias


Alto rendimiento

  • trading
  • analytics
  • cálculos intensivos


Menos GC = mejor performance


¿Qué cambia realmente?

Sin Valhalla:

List<Point> // lista de referencias


Con Valhalla:

[x1, y1, x2, y2, x3, y3]


Datos planos → mejor cache → más velocidad


Cuándo NO usar Valhalla

  • Entidades (`User`, `Order`)
  • Objetos con identidad
  • Integración con frameworks clásicos


Si necesitás identidad → no es value type

Lo mejor: combinarlos

Acá está la clave real 👇


Caso 1: Record + Value Type


value class Point {

    int x, y;

}


record Circle(Point center, double radius) {}


Tenés:

API clara (record)

datos eficientes (value)


Caso 2: separación por capas


// API

record PointDTO(int x, int y) {}


// Core

value class Point {

    int x, y;

}


Separás:

  • interfaz → legible
  • core → performante


Caso 3: colecciones grandes


value class Price {

    double amount;

}


List<Price>


Sin boxing → sin referencias → 🔥


Futuro: value records

Se viene algo así:

value record Point(int x, int y) {}


Combina:

  • simplicidad (record)
  • eficiencia (value type)


Conclusión, no es una pelea, es una estrategia:

  • Records → hacen feliz al desarrollador
  • Valhalla → hace feliz a la JVM



Java vs C#: Records y Value Types vs Records y Structs


Durante años, C# llevó ventaja en expresividad y control de memoria.

Pero con Java Records y Project Valhalla, Java está alcanzando… y en algunos aspectos, intentando superarlo.


👉 La pregunta es:

 ¿Java está copiando a C#… o lo está mejorando?


Empecemos por records: empate técnico

En C#

record Person(string Name);


En Java

record Person(String name) {}


✔ Inmutables

✔ Comparación por valor

✔ Menos boilerplate


Conclusión: Empate total — ambos lenguajes convergieron al mismo concepto


Value Types vs Structs

En C#: struct


struct Point {

    public int X;

    public int Y;

}


✔ Tipo por valor

✔ Generalmente en stack

✔ Muy eficiente


Problemas:

Boxing (se convierte en objeto)

Copias implícitas

Comportamiento a veces confuso


 En Java: Value Types (Valhalla)


value class Point {

    int x, y;

}


✔ Sin identidad

✔ Sin overhead de objeto

✔ Puede ser “flattened”


Y lo más importante: No cambia su naturaleza según el contexto


Diferencia clave

C# → tipo híbrido (a veces valor, a veces objeto)

Java → tipo consistente (siempre value type)


Punto para Java (a nivel diseño)


Memoria y layout

  • Stack vs Heap
  • Depende del contexto
  • Puede generar copias innecesarias


 Java (Valhalla)

  • Flattening automático
  • Mejor locality
  • Optimización por la JVM


Ejemplo mental:

En java esto: 

List<Point>


Podría ser:

[x1, y1, x2, y2, x3, y3]


Mucho más eficiente que referencias



Generics (el golpe fuerte de Java)


C#

List<int> 


Soportado desde hace años


Java (hoy)

List<Integer>  (boxing)


Java (con Valhalla)

List<int> ✔

List<Point> ✔


Sin boxing y sin referencias


Este es uno de los mayores avances de Java


Complejidad del modelo mental


En C#

  • class vs struct
  • boxing/unboxing
  • copias implícitas
  • Puede ser confuso


En Java

  • class vs value class
  • sin identidad vs con identidad
  • Más simple conceptualmente


Ecosistema y madurez

C#

✔ Ya está en producción

✔ Frameworks adaptados

✔ Casos reales


 Java (Valhalla)

⚠️ En desarrollo

⚠️ APIs en evolución

⚠️ Falta adopción


Hoy no podés usarlo en producción estándar



¿Quién lo hizo mejor?


Hoy: C#

Porque:

  • ya funciona
  • es estable
  • está probado


 A futuro: Java (posiblemente)

Porque:

  • evita errores históricos (boxing, copias)
  • diseño más consistente
  • mejor integración con la JVM



HTTP 418: I'm a teapot


Si alguna vez viste el código HTTP 418, probablemente pensaste: “¿Esto es real o me están trolleando?”

Spoiler: ambas cosas.


¿Qué significa el error 418?

El código HTTP 418 – "I'm a teapot" es un código de error del cliente (4xx) que, literalmente, significa:

 “Soy una tetera y no puedo hacer café” 


La idea es simple:

El cliente hace una request (ej: “haceme café” ☕)

El servidor responde:

  “No puedo, soy una tetera”


Este código nace en 1998 en el RFC 2324, llamado:

Hyper Text Coffee Pot Control Protocol (HTCPCP)


Sí, un protocolo para controlar cafeteras por internet… y sí, fue publicado el 1 de abril (April Fools). 


La especificación decía cosas como:

  • Método HTTP: BREW
  • Headers para azúcar o leche
  • Y este glorioso error 418

 ¿Es un chiste o es real?

Las dos:

  • Es parte “oficial” del ecosistema HTTP (aunque reservado/no usado formalmente) 
  • No tiene uso serio en producción
  • Pero muchos frameworks lo incluyen igual


Ejemplos reales:

  • Java / Spring: podés devolver 418
  • .NET: `StatusCodes.Status418ImATeapot`
  • Node / Go / Python también lo soportan 


¿Se usa en la vida real?

No debería… pero igual aparece:

  • Easter eggs en APIs
  • Testing de errores
  • Bloqueo de bots
  • Mensajes humorísticos para developers


Incluso hay devs que lo usan para decir: “Tu request es absurda”


Dejo link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/418

Proyecto Valhalla en Java: Tipos de Valor y el Futuro del Rendimiento


Cuando hablamos de la evolución de Java, uno de los proyectos más interesantes (y menos comprendidos) es Project Valhalla.


Si alguna vez sentiste que Java es “pesado” por culpa de los objetos… este proyecto apunta directamente a eso.

Project Valhalla es una iniciativa dentro de OpenJDK cuyo objetivo principal es introducir:

Tipos de valor (Value Types / Inline Classes)

Esto permite representar datos sin el costo de los objetos tradicionales.

En Java, casi todo es un objeto… y eso tiene consecuencias:


Integer x = 10;


Esto implica:

  • Heap allocation
  • Indirección (punteros)
  • Presión sobre el GC
  • Mala localización en memoria (cache-unfriendly)


Incluso algo simple como una lista de enteros:


List<Integer>


Es en realidad:

List -> referencias -> objetos Integer


¿Qué propone Valhalla?


Valhalla introduce un nuevo tipo de clases: Clases inline (value classes)


Ejemplo conceptual:


value class Point {

    int x;

    int y;

}


Esto permite:

  • Sin identidad (no == por referencia)
  • Sin overhead de objeto
  • Layout compacto en memoria


¿Por qué esto es importante?


Mejora de rendimiento

  • Menos uso de heap
  • Mejor uso de CPU cache
  • Menos GC


Estructuras más eficientes


Ejemplo:

List<Point>


Con Valhalla podría ser:

[ x1, y1, x2, y2, x3, y3 ]


👉 En lugar de:

[ ref -> Point, ref -> Point, ref -> Point ]


Conceptos clave de Valhalla


Value Objects

  • No tienen identidad, la identidad esta dada por su propio valor
  • Son inmutables (conceptualmente)
  • Se comparan por contenido


Flattening

El JVM puede “aplanar” estructuras:


class Line {

    Point p1;

    Point p2;

}


En memoria:

[x1, y1, x2, y2]


Specialized Generics (futuro)

Uno de los grandes problemas actuales:

List<int> ❌

List<Integer> ✅ (pero lento)


Valhalla busca permitir:

List<int> ✅


Sin boxing


Cambios importantes a tener en cuenta

  • No todo será automáticamente value type
  • Cambia el modelo mental (menos identidad, más datos)
  • Impacta librerías y frameworks


Project Valhalla aún está en desarrollo activo.

No es parte estable de Java todavía, pero ya hay:

  • Prototipos en OpenJDK
  • Features en incubación


Veamos un ejemplo: 


 Antes (Java actual)


class Complex {

    double re;

    double im;

}


  • Objeto en heap
  • Referencias


Con Valhalla (ideal)


value class Complex {

    double re;

    double im;

}


  • Datos contiguos
  • Sin overhead




Project Valhalla busca algo muy ambicioso:

Combinar lo mejor de OOP con la eficiencia de lenguajes de bajo nivel


En otras palabras:

  • Mantener la simplicidad de Java
  • Reducir el costo de abstracción


En C# tenemos el struct que es muy similar a lo que busca Valhalla.


miércoles, 22 de abril de 2026

C++26: El salto más grande desde C++11


La nueva versión del estándar, C++26, ya está prácticamente cerrada… y no es una actualización menor.


Estamos hablando de una versión que introduce:

  • Reflection (reflexión)
  • Mejoras reales en seguridad de memoria
  • Contracts (programación por contratos)
  • Un nuevo modelo async/concurrencia


En conjunto, esto posiciona a C++ como un lenguaje que quiere competir con Rust en seguridad y con lenguajes modernos en expresividad… sin perder su filosofía de zero-overhead. 


Reflection: C++ ahora puede “mirarse a sí mismo”

La reflection en tiempo de compilación es probablemente el cambio más disruptivo.

¿Qué significa?

Que el código puede inspeccionar tipos, atributos y estructuras en compile-time.


Antes:

  • Macros
  • Templates imposibles de leer
  • Mucho boilerplate


Ahora:

  • Metaprogramación más directa
  • Generación automática de código
  • Mejor tooling


Ejemplo conceptual:

enum Color { red, green, blue };

static_assert(enum_to_string(Color::red) == "red");



Esto antes era doloroso; ahora es natural.

Es compile-time es decir, no tiene costo en runtime


Impacto real:

  • Serialización automática
  • ORMs más simples
  • Validaciones generadas
  • DSLs internas más potentes


Seguridad de memoria (sin romper C++)


C++26 no intenta ser “safe by default” como Rust.

En cambio, introduce mejoras pragmáticas:

  • Librerías con chequeo de bounds
  • Mejor manejo de variables no inicializadas
  • Eliminación de ciertos comportamientos indefinidos
  • Opciones “hardened” del estándar


No requiere reescribir tu código existente


Esto es muy C++:

  • No rompe compatibilidad
  • Permite adopción gradual


Contracts: diseño por contrato (por fin)

Después de años de idas y vueltas, llegan los contracts:


[[pre: x > 0]]

[[post: result >= 0]]

int sqrt(int x);


También aparece:

contract_assert(...)


¿Qué aportan?

  • Validación de precondiciones
  • Validación de postcondiciones
  • Documentación ejecutable
  • Mejor debugging


Es básicamente traer ideas de:

  • Eiffel
  • Ada
  • .NET Code Contracts

Pero ahora en C++ estándar.


Nuevo modelo async: sender/receiver


C++ llevaba años con:

  • std::thread
  • std::future
  • async


Pero nada realmente composable.


Ahora aparece un modelo basado en sender / receiver


Características:

  • Composición funcional de tareas
  • Concurrencia estructurada
  • Mejor integración con coroutines
  • Pipeline de operaciones async


Esto unifica:

  • paralelismo
  • asincronía
  • ejecución


Similar conceptualmente a:

  • Reactive Streams
  • Rx
  • pipelines funcionales


C++26 no es una evolución incremental.

Es un intento claro de:

  • Modernizar el lenguaje
  • Mantener compatibilidad
  • Competir con Rust y lenguajes modernos


martes, 21 de abril de 2026

Records vs Clases vs Lombok vs Kotlin vs Scala


¿Cuál es la mejor forma de modelar datos? Desde los Struct de c++ nos venimos preguntando esto. Vamos a ver algunas opciones modernas que nos provee la plataforma java. 

Cuando trabajamos con objetos que representan datos (DTOs, Value Objects, etc.), distintos lenguajes ofrecen soluciones para evitar el boilerplate.


En este post comparamos:

  • Records en Java
  • Clases tradicionales
  • Lombok
  • Data classes en Kotlin
  • Case classes en Scala


1. Clase tradicional (Java)


public class Persona {

    private final String nombre;

    private final int edad;


    public Persona(String nombre, int edad) {

        this.nombre = nombre;

        this.edad = edad;

    }


    public String getNombre() { return nombre; }

    public int getEdad() { return edad; }


    @Override public boolean equals(Object o) { ... }

    @Override public int hashCode() { ... }

    @Override public String toString() { ... }

}

Ventajas

  • Total control
  • Compatible con todo (JPA, frameworks)


Desventajas

  • Mucho boilerplate
  • Propenso a errores


2. Records (Java)


public record Persona(String nombre, int edad) {}


Ventajas

  • Ultra conciso
  • Inmutabilidad garantizada
  • Sin dependencias


Desventajas

  • Menos flexible
  • No sirve bien con JPA
  • No herencia


3. Lombok (@Data)


import lombok.Data;


@Data

public class Persona {

    private String nombre;

    private int edad;

}


Ventajas

  • Reduce mucho código
  • Mutable o inmutable (configurable)


Desventajas

  • Dependencia externa
  • "Magia" en compilación (puede confundir)
  •  Problemas en tooling/debug


4. Data Classes (Kotlin)


data class Persona(val nombre: String, val edad: Int)


Ventajas

  • Muy conciso
  • Inmutable por defecto
  • copy() incluido
  • Destructuring


val (nombre, edad) = persona


Desventajas

  • Requiere usar Kotlin
  • Interoperabilidad Java no siempre perfecta


5. Case Classes (Scala)


case class Persona(nombre: String, edad: Int)


Ventajas

  • Inmutables
  • Pattern matching nativo
  • copy() automático
  • Muy expresivas


persona match {

  case Persona(nombre, edad) => println(nombre)

}


Desventajas

  • Curva de aprendizaje
  • Ecosistema más complejo


Y entonces? Y ninguno es super mejor, pero podemos tener estas reglas: 


Java Records

Ideal para:

  • DTOs simples
  • APIs REST
  • Código moderno sin dependencias


Son el "mínimo viable elegante" en Java.


Lombok

Ideal para:

  • Proyectos legacy
  • Equipos que ya lo usan


 Soluciona el problema… pero no es parte del lenguaje.


Kotlin

La mejor experiencia general para modelado de datos.

  • copy()
  • destructuring
  • null-safety


Es claramente superior en ergonomía.


Scala

El más poderoso conceptualmente.

  • Pattern matching real
  • Inmutabilidad fuerte
  • Integración con FP


Pero más complejo.


 Clases Java

 Siguen siendo necesarias cuando:

  • Usás JPA
  • Necesitás mutabilidad
  • Requerís control total


Si estás en Java moderno → Records

Si querés máxima productividad → Kotlin

Si buscás poder expresivo → Scala

Si estás en legacy → Lombok o clases



lunes, 20 de abril de 2026

Records en Java: Datos Inmutables de Forma Elegante


Desde Java 14, el lenguaje incorporó una nueva forma de definir clases de datos: los records.

Su objetivo es simple: reducir el boilerplate cuando solo queremos representar datos inmutables.


¿Qué problema vienen a resolver?

Antes de records, una clase típica para representar datos se veía así:


public class Persona {

    private final String nombre;

    private final int edad;


    public Persona(String nombre, int edad) {

        this.nombre = nombre;

        this.edad = edad;

    }


    public String getNombre() {

        return nombre;

    }


    public int getEdad() {

        return edad;

    }


    @Override

    public boolean equals(Object o) { ... }


    @Override

    public int hashCode() { ... }


    @Override

    public String toString() { ... }

}


Mucho código repetitivo, ¿no?

Con records, lo mismo se define así:


public record Persona(String nombre, int edad) {}


Y listo.


Java automáticamente genera:

  • Constructor
  • Getters (sin prefijo get)
  • equals()
  • hashCode()
  • toString()


Un record es una clase especial que:

  • Es inmutable
  • Es final
  • Extiende implícitamente de java.lang.Record


Persona p = new Persona("Juan", 30);

System.out.println(p.nombre()); // Juan

System.out.println(p.edad());   // 30


Podemos hacer un constructor personalizado por ejemplo para validar datos:


public record Persona(String nombre, int edad) {

    public Persona {

        if (edad < 0) {

            throw new IllegalArgumentException("Edad inválida");

        }

    }

}


Este es un constructor compacto.

Los records no son solo datos, también pueden tener lógica:


public record Persona(String nombre, int edad) {

    public boolean esMayorDeEdad() {

        return edad >= 18;

    }

}


Restricciones importantes:

  • No podés extender otras clases
  • Los atributos son implícitamente final
  • No hay setters
  • No están pensados para entidades mutables (ej: JPA)


¿Cuándo usar Records?

Usalos cuando:

✔ Tenés objetos de solo datos (DTOs)

✔ Querés inmutabilidad

✔ Buscás claridad y menos boilerplate


Evitarlos cuando:

❌ Necesitás mutabilidad

❌ Estás modelando entidades complejas

❌ Usás frameworks que requieren setters (como JPA tradicional)


Con features modernas (Java 21+), los records se integran muy bien con pattern matching:


if (obj instanceof Persona(String nombre, int edad)) {

    System.out.println(nombre);

}


Esto hace el código más declarativo y expresivo.


Los records son una de las mejoras más importantes en Java moderno:

  • Reducen código repetitivo
  • Fomentan inmutabilidad
  • Mejoran la legibilidad


Son ideales para modelar datos de forma clara y segura.

domingo, 19 de abril de 2026

¿Por qué Java usa Streams?


Cuando Java introdujo Streams en Java 8, no fue solo para “hacer código más lindo”, sino para cambiar la forma en que procesamos colecciones.


Pero otros lenguajes de la JVM ya resolvían esto de forma distinta.

Entonces, la pregunta es: ¿por qué Java eligió Streams y no otro modelo?


Antes de Java 8:

List<String> result = new ArrayList<>();

for (String s : lista) {

    if (s.length() > 3) {

        result.add(s.toUpperCase());

    }

}


Mucho boilerplate

  • No es declarativo
  • Difícil de paralelizar
  • Mezcla lógica con control de flujo


La solución: Streams en Java


Con Streams:


List<String> result = lista.stream()

    .filter(s -> s.length() > 3)

    .map(String::toUpperCase)

    .toList();


Claves del diseño:

  • Evaluación lazy
  • Pipeline de operaciones
  • Separación entre datos y procesamiento
  • Fácil paralelización (parallelStream())


Java construyó un modelo nuevo, no solo métodos en Collection ¿y por qué? Otros lenguajes los hacían bien. 

Scala

lista.filter(_.length > 3).map(_.toUpperCase)


Características

  • Colecciones inmutables por defecto
  • Operaciones directamente sobre la colección
  • Lazy solo si usás View o LazyList

Scala no necesita Streams porque su API de colecciones ya es funcional


Kotlin

lista.filter { it.length > 3 }

     .map { it.uppercase() }


Características:

  • API funcional sobre colecciones
  • Operaciones eager por defecto


Para lazy:

lista.asSequence()

    .filter { it.length > 3 }

    .map { it.uppercase() }


Diferencia clave

Kotlin separa:

  • List (eager)
  • Sequence (lazy)


Java unificó esto en Streams.


Groovy

lista.findAll { it.length() > 3 }

     .collect { it.toUpperCase() }


Características

  • Muy expresivo
  • Dinámico
  • API funcional desde hace años


Diferencia clave

Más simple, pero:

  • menos eficiente
  • no lazy por defecto
  • sin optimización tipo pipeline


Entonces ¿Por qué Java eligió Streams?


Java tenía restricciones fuertes:

1. Compatibilidad hacia atrás, no podía romper Collection

2. Necesidad de lazy evaluation para evitar:

  • listas intermedias
  • consumo extra de memoria


3. Paralelismo

Streams permiten: lista.parallelStream() sin cambiar el código lógico


4. Pipeline optimizable


La JVM puede optimizar: filter → map → reduce, como una sola operación


Java no eligió Streams por casualidad.

Fue una decisión para:

  • mantener compatibilidad
  • introducir programación funcional
  • mejorar performance
  • habilitar paralelismo


Mientras otros lenguajes:

  • ya eran funcionales (Scala)
  • o tomaron caminos más simples (Kotlin, Groovy)



sábado, 18 de abril de 2026

Java 26: Hacia dónde evoluciona la plataforma


Java 26 representa una versión en evolución dentro del ciclo de releases de Java, donde se profundizan cambios importantes en concurrencia, rendimiento y modelo de datos.

Tipo de release: No LTS

Estado: 🧪 En desarrollo / Early Access

Enfoque: innovación + maduración de features clave


Concurrencia (Project Loom)

Java continúa consolidando un nuevo modelo de concurrencia.


Structured Concurrency (posible estabilización)

Permite agrupar tareas relacionadas como una unidad lógica

Simplifica:

  • manejo de errores
  • cancelación
  • sincronización


Hace que el código concurrente sea más legible y seguro


Virtual Threads (optimización continua)

  • Mejor integración con APIs existentes
  • Ajustes de rendimiento
  • Mayor adopción en frameworks


Lenguaje: menos boilerplate


Pattern Matching (más evolución)

  • Código más declarativo
  • Reducción de casts explícitos
  • Mejor integración con `switch`


Java sigue acercándose a un estilo más expresivo sin perder claridad.

Interoperabilidad nativa

Foreign Function & Memory API (FFM)

  • Más cerca de ser estándar definitivo
  • Alternativa real a JNI


Permite:

  • acceso eficiente a memoria off-heap
  • llamadas a librerías nativas


Clave para aplicaciones de alto rendimiento


Proyecto Valhalla (avance gradual)

Uno de los cambios más importantes a largo plazo.


Value Objects (en progreso)

  • Objetos sin identidad
  • Mejor uso de memoria
  • Mayor eficiencia en estructuras de datos


Impacto esperado:

  • colecciones más rápidas
  • menos overhead de objetos


JVM y rendimiento


  • Mejoras continuas en:
    • G1
    • ZGC
  • Optimización del JIT
  • Mejor uso de CPU moderna


Java 26 no es una versión de adopción masiva, sino una versión que:

  • empuja nuevas ideas
  • estabiliza features incubadas
  • prepara cambios grandes a futuro


miércoles, 15 de abril de 2026

¿Qué es LLVM? Introducción a la infraestructura detrás de los compiladores modernos


Si alguna vez te preguntaste cómo lenguajes como Rust o Swift generan código tan eficiente…

La respuesta probablemente sea: LLVM. LLVM no es un compilador tradicional es una infraestructura para construir compiladores.


Durante años, herramientas como GCC siguieron este modelo:

  • Todo en uno (frontend + optimización + backend)
  • Difícil de extender
  • Costoso crear nuevos lenguajes


Resultado: crear un lenguaje era MUY complejo


LLVM cambia el enfoque: Separar el compilador en piezas reutilizables


¿Cómo funciona LLVM?

El proceso se divide en 3 partes:

Frontend

  • Convierte tu lenguaje a LLVM IR
  • Cada lenguaje define su frontend


LLVM IR (Intermediate Representation)

Es el corazón del sistema:

  • Representación intermedia
  • Independiente del hardware
  • Optimizable


Ejemplo:

llvm id="u7j1k0"

define i32 @main() {

  %1 = add i32 10, 20

  ret i32 %1

}


Un “lenguaje común” entre todos los compiladores


Backend

Convierte el IR en código máquina:

  • x86
  • ARM
  • RISC-V

LLVM se encarga de esto


¿Por qué es tan importante? Porque reduce drásticamente la complejidad:

Antes: Lenguaje = compilador completo

Ahora: Lenguaje = frontend + LLVM


LLVM es muy usado, entre los lenguajes que lo usan podemos encontrar:

  • Rust
  • Swift
  • C/C++ con Clang
  • Kotlin Native


LLVM separa responsabilidades:

  • Lenguaje → Frontend
  • Optimización → LLVM
  • Hardware → Backend


Esto permite innovación más rápida y reutilización masiva

LLVM es el motivo por el cual hoy crear un lenguaje es mucho más accesible que antes.

martes, 14 de abril de 2026

Alias en imports en Java: lo que no existe (y cómo resolverlo)


Cuando venís de otros lenguajes, es común esperar algo como esto:

import com.ejemplo.A as A1; // ❌


Pero en Java esto simplemente no existe.


 ¿Qué son los alias en imports?


Un alias permite:

  • Importar dos clases con el mismo nombre
  • Y diferenciarlas con nombres alternativos


Ejemplo típico en otros lenguajes:


Kotlin

import com.ejemplo.a.Clase as ClaseA

import com.ejemplo.b.Clase as ClaseB


Scala

import com.ejemplo.a.{Clase => ClaseA}

import com.ejemplo.b.{Clase => ClaseB}


C#

using ClaseA = Ejemplo.A.Clase;

using ClaseB = Ejemplo.B.Clase;


¿Qué pasa en Java?


Si tenés dos clases con el mismo nombre:


import com.ejemplo.a.Clase;

import com.ejemplo.b.Clase; // ❌ conflicto


Java no sabe cuál usar.

La solución es tenés que usar el nombre completo en al menos uno:


import com.ejemplo.a.Clase;


public class Main {

    public static void main(String[] args) {

        Clase a = new Clase();

        com.ejemplo.b.Clase b = new com.ejemplo.b.Clase();

    }

}


¿Por qué Java no tiene alias?


El lenguaje prioriza:

  • Simplicidad
  • Legibilidad explícita
  • Evitar ambigüedades en compilación

No hay transformación de nombres en imports


Problemas reales que genera:

  • Código más verboso
  • Menor ergonomía
  • Conflictos frecuentes en proyectos grandes
  • Difícil integración entre librerías con naming similar

Java no soporta alias en imports y la solución es usar nombres completos. Pero otros lenguajes modernos sí lo resuelven mejor


viernes, 10 de abril de 2026

Java 25: Evolución y consolidación de la plataforma


Java SE 25 continúa el camino de modernización de Java, con foco en concurrencia, rendimiento y maduración de features introducidas en versiones anteriores.

Ojo es No LTS


Concurrencia (Project Loom)


Java sigue apostando fuerte por la concurrencia moderna.

Virtual Threads (madurez)

  • Totalmente integrados en el ecosistema
  • Mejoras en estabilidad y rendimiento
  • Transparencia casi total respecto a threads tradicionales


Beneficio clave: Escalar a miles de tareas concurrentes sin complejidad extra


Scoped Values (evolución)

Alternativa moderna a ThreadLocal:


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


ScopedValue.where(user, "Emanuel").run(() -> {

    System.out.println(user.get());

});


  • Inmutables
  • Seguros en entornos concurrentes
  • Ideales para usar con Virtual Threads


Structured Concurrency (avance)

  • Mejor organización de tareas relacionadas
  • Manejo más claro de errores y cancelaciones
  • Código más predecible


Lenguaje: más simple y expresivo


Pattern Matching (refinamientos)

  • Mejoras en switch
  • Menos casting manual
  • Código más limpio


switch (obj) {

    case String s -> System.out.println(s);

    case null -> System.out.println("null");

    default -> {}

}


Interoperabilidad


Foreign Function & Memory API

  • Más estable y usable
  • Reemplazo progresivo de JNI


Permite:

  • llamar a código nativo
  • manejar memoria off-heap de forma segura


JVM y rendimiento

Garbage Collectors


Mejoras continuas en:

  • G1
  • ZGC


Optimizaciones generales

  • Menor latencia
  • Mejor throughput
  • Ajustes en el JIT


Ecosistema

  • Mejor integración con frameworks modernos
  • Tooling más alineado con Virtual Threads
  • Preparación para proyectos futuros como Valhalla


Java 25 no busca revolucionar, sino consolidar lo que ya empezó a cambiar Java profundamente:

  • Concurrencia moderna ya usable en producción
  • Lenguaje más expresivo
  • Mejor performance


Acelera la innovación de la IA con contenedores

 Me llegó este mail de google y lo quería compartir : 

martes, 7 de abril de 2026

Java 24: Novedades y características principales


Java SE 24 continúa la evolución de la plataforma con foco en rendimiento, concurrencia y simplificación del lenguaje.

Ojo es no LTS!


Concurrencia moderna (Project Loom)

Uno de los ejes más importantes sigue siendo la evolución de la concurrencia.


Virtual Threads (mejoras)

  • Threads livianos gestionados por la JVM
  • Permiten manejar miles o millones de tareas concurrentes
  • Menor costo que los threads tradicionales


Structured Concurrency (incubating)

  • Permite tratar múltiples tareas como una sola unidad lógica
  • Mejora el manejo de errores y cancelaciones


Ejemplo conceptual:


try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {

    scope.fork(() -> servicioA());

    scope.fork(() -> servicioB());

    scope.join();

    scope.throwIfFailed();

}


Lenguaje: más expresividad


Pattern Matching (evolución)

  • Mejora continua en switch
  • Código más declarativo y menos verboso


switch (obj) {

    case String s -> System.out.println(s.length());

    case Integer i -> System.out.println(i * 2);

    default -> {}

}


Interoperabilidad nativa

Foreign Function & Memory API (evolución)

  • Reemplazo moderno de JNI
  • Acceso seguro a memoria fuera del heap
  • Llamadas a código nativo (C/C++)


Beneficios:

  • más performance
  •  menos complejidad que JNI


Rendimiento y JVM

Garbage Collectors

Mejoras en:

  • G1
  • ZGC


Optimizaciones generales

  • Mejor uso de CPU y memoria
  • Reducción de pausas


Otras mejoras

  • Refinamientos en APIs estándar
  • Mejoras internas en la JVM
  • Preparación para futuros proyectos como Valhalla


Java 24 no introduce cambios “revolucionarios”, pero sí consolida tendencias clave:

  • Concurrencia moderna (Loom)
  • Código más expresivo (Pattern Matching)
  • Mejor interoperabilidad (FFM API)
  • Performance constante


Es una versión que prepara el terreno para cambios más grandes en futuras releases.