O JEP 401 (Value Objects - Preview) foi integrado ao JDK 28, marcando a primeira entrega tangível do Project Valhalla. A proposta introduz value classes — instâncias sem identidade, compostas exclusivamente por campos final — e redefine a semântica do operador == para esses tipos, comparando estrutura e não referência.
O que muda para o desenvolvedor<\/h2>
Uma classe declarada com o modificador value torna-se uma value class; todas as demais permanecem identity classes. As regras de construção são estritas:
- Campos de instância são implicitamente
final; - Todos os campos devem ser inicializados antes que a instância se torne observável;
- Métodos de instância não podem ser
synchronized; - Records também aceitam o modificador:
value record Color(byte r, byte g, byte b) {}.
A verificação bytecode que garante essas regras vem do JEP 539 (Strict Field Initialization). O recurso está desabilitado por padrão — exige --enable-preview em tempo de compilação e execução.
O novo ==: igualdade por conteúdo
Para identity objects, o comportamento de == não muda. Para value objects, o operador retorna true quando ambos operandos são da mesma classe e possuem os mesmos valores de campo (campos de referência são comparados recursivamente com ==).
value class Point { int x; int y; }
Point p1 = new Point(3, 4);
Point p2 = new Point(3, 4);
assert p1 == p2; // true: mesma classe, mesmos campos
Object o1 = p1, o2 = p2;
assert o1 == o2; // true: ainda indistinguíveis como Object
String s1 = "hamburger\);
String s2 = new String(s1);
assert s1 != s2; // true: String continua sendo identity class
Atenção: o JEP 401 não propõe == como substituto de equals(). A recomendação de usar equals() para comparação semântica permanece, pois o estado interno de um value object nem sempre equivale ao estado que ele representa.
Migração de classes do jdk<\/h2>
Com a preview habilitada, diversas classes value-based do JDK — wrappers primitivos (Integer, Double, etc.) e LocalDate, entre outras — passam a ser value classes. Com a preview desabilitada, o compilador mantém suas formas de identidade e o comportamento alinhado ao JDK 27.
- Código compilado com preview precisa rodar com preview habilitado;
- Recompilação é recomendada para classes migradas — o atributo
LoadableDescriptorsno class file informa à JVM que a classe é uma value class; - Algumas APIs deixam de funcionar: criar
Referencepara value object lançaIdentityException; - O
javacestende seus avisos de identidade para value classes no JDK 28.
Ganhos de performance: otimização, não garantia<\/h2>
O payoff esperado é otimização da JVM, não resultado de benchmark garantido. A JVM pode:
- Scalarizar o value object em seus campos constituintes;
- Achatar (flatten) em representação compacta armazenada diretamente em campo ou elemento de array;
- Fazer fallback para alocação ordinária quando nenhuma otimização se aplica (especialmente durante warmup, antes de código JIT otimizado estar disponível).
O achatamento permanece limitado pela atomicidade; em plataformas típicas, a codificação disponível pode ser tão pequena quanto 64 bits incluindo flag de null.
Motivação: desalinhamento entre intenção e garantia<\/h2>
O JEP enquadra o problema como um mismatch entre o que desenvolvedores querem (tipos pequenos que carregam dados — número complexo, cor de pixel, data) e o que Java garante: todo new produz algo distinguível de qualquer outro objeto. Para esses tipos, a identidade é frequentemente irrelevante e prejudicial.
A identidade carrega custo de execução: alocação por objeto, desreferência a cada uso, pressão no GC e degradação de localidade. Escape analysis recupera parte disso, mas suas otimizações são imprevisíveis e não ajudam quando o objeto escapa (ex.: armazenado em campo ou array).
Impactos e considerações de segurança<\/h2>
- Desenvolvedores podem se surpreender com o novo comportamento de
== e synchronized, embora a proposta espere disrupções incomuns e gerenciáveis;
- O bytecode
if_acmpeq ganha verificação adicional para value objects, mantendo o caso de identidade como fast path;
- Duas considerações de segurança:
== e identityHashCode podem expor indiretamente valores de campos private; comparar duas árvores grandes de value objects pode consumir tempo ilimitado.
== e synchronized, embora a proposta espere disrupções incomuns e gerenciáveis;if_acmpeq ganha verificação adicional para value objects, mantendo o caso de identidade como fast path;== e identityHashCode podem expor indiretamente valores de campos private; comparar duas árvores grandes de value objects pode consumir tempo ilimitado.Fonte original: InfoQ — "Project Valhalla's First Preview: JEP 401 Redefines == for Java Objects" (10/08/2026).