Technology

Project Valhalla Preview: JEP 401 Redefines Object Equality in Java

A preview of Project Valhalla has been integrated into JDK 28, introducing value objects that redefine how the `==` operator works and open the door to flat, allocation-free JVM representations.

JEP 401 introduces a preview of Project Valhalla's Value Objects to JDK 28, redefining the `==` operator for value-based classes. This feature allows for field-by-field equality comparison and opens the door to flatter, allocation-free JVM representations. The preview is disabled by default and has implications for migration, compatibility, and optimization, offering the potential for significant performance gains while also introducing security considerations.

A significant milestone for the Java ecosystem has arrived. Project Valhalla's first preview, detailed in JEP 401: Value Objects, has been integrated into JDK 28. This is a major step in overhauling Java's object model to address a long-standing mismatch between what developers mean and what Java guarantees.

The preview introduces identity-free class instances with only final fields. For these objects, the behavior of the == operator is redefined to perform a field-by-field comparison, rather than checking reference identity. This change opens the door to flatter, allocation-free JVM representations, which could bring significant performance benefits to the platform.

The preview is disabled by default and requires the --enable-preview flag at both compile time and run time.

The Semantics of Value

A class declared with the value modifier is a value class. Every other class remains an identity class. Value class instances have no identity, meaning two different instances with the same field values are considered equal. The fields of a value class are implicitly final, and every field must be assigned before the new instance can be observed. Records, which are already a form of data carrier, can also take the value modifier.

This semantic change is most visible with the == operator. For identity objects, its behavior remains unchanged. For value objects, == succeeds when both operands are instances of the same class with the same field values. Reference-typed fields are compared recursively using equals.

This is not an invitation to abandon equals. JEP 401 does not redefine == as a replacement for equals; the usual advice to compare objects using equals still applies because a value object's internal state is not always the same as the state it represents.

Migration and Compatibility

With preview features enabled, several value-based JDK classes, including primitive wrappers and LocalDateTime, are transitioned to become value classes. With preview disabled, the compiler continues to use its identity-object forms.

Code compiled with the preview enabled must also run with it enabled. Recompilation is recommended for migrated classes because the class-file attribute tells the JVM at load time that a class is a value class.

Some APIs stop working. For example, creating a synchronized block for a value object throws an exception. The Identity class extends its identity warnings to value classes in JDK 28.

Performance and Optimization

The expected payoff of JEP 401 is not a guaranteed benchmark result but an optimization opportunity. A JVM can scalarize a value object into its constituent fields or flatten it into a compact representation stored directly in a field or array element. This can significantly reduce memory footprint and garbage collection pressure.

When these optimizations don't apply, the JVM falls back to ordinary allocation, especially during warmup before optimized JIT code is available. Flattening is also constrained by atomicity, with platforms limiting encoding to as small as 64 bits.

A Fundamental Shift

JEP 401 frames the problem as a mismatch between what developers mean and what Java guarantees. Small classes representing a complex number, pixel color, or date exist to carry data. Yet ordinary Java objects are defined by identity: every constructor call produces something distinguishable from every other object. For such types, the JEP argues, identity is often irrelevant and can be harmful.

The JEP acknowledges that value objects make significant changes to Java's object model. However, the proposal expects disruptions to be uncommon and manageable. The document also identifies two security considerations: toString and equals may indirectly expose private field values, and comparing two large trees of value objects may take unbounded time.