The Decade-Long Wait Is Over: Value Classes Land in JDK 28

On June 15, Oracle engineer Lois Foltan confirmed that JEP 401, Value Classes and Objects, has been integrated into the main OpenJDK repository and is targeting JDK 28. The pull request alone adds over 197,000 lines of code across 1,816 files. This is the first deliverable from Project Valhalla, a project that started in 2014 with the goal of making user-defined types as efficient as primitives while retaining the expressiveness of classes.

But hold the champagne: this is a preview feature, disabled by default. Brian Goetz was quick to temper expectations: "only the first part of Valhalla." The community joke that we'd reach the Norse Valhalla before Project Valhalla ships now shifts to "but they didn't ship the most important part."

The Problem: Fluffy Objects and Cache Misses

Java's type system has eight primitives (int, long, double, boolean, etc.) and everything else is a reference type. When you write Point p = new Point(1, 2), p is not a point—it's a pointer to an object on the heap. Every field access requires a pointer indirection (a "hop"). For a single object, that's negligible. But at scale, every object has a header (a dozen or so bytes), allocation overhead, and garbage collection costs. An array of a million Points is a million pointers scattered across the heap.

Brian Goetz calls this memory layout "fluffy." The hardware has changed dramatically since 1995: memory access is now ~100x slower than CPU, bridged by caches. Cache lines are 64 bytes. If data is dense and sequential, one cache line brings in many useful values. Pointer hopping causes cache misses, which can be a hundred times slower than a hit.

Escape analysis can sometimes optimize objects away, but it's fragile. A minor refactor, JDK update, or method boundary change can send objects back to the heap. The alternative—hand-encoding data as raw primitives—sacrifices safety, readability, and maintainability. JEP 401 gives the example of a developer mistakenly interpreting raw color bytes as BGR instead of RGB, corrupting an entire image. A class wouldn't allow that; a bare int would.

The Evolution: From Q World to L World to Today

Project Valhalla officially started in 2014. Over the years, the team built five different prototypes. Early prototypes ("Q World") treated value types as completely separate from objects—with distinct type descriptors, bytecodes, and top types. That approach flooded the JVM with complexity.

The breakthrough came around 2019 with "L World," where value types shared the same "L" descriptor as object references. To the team's surprise, this worked without major compromises. The key insight: the language model and the JVM model don't have to overlap 100%. L World is the right VM model, and you can translate it to a more convenient language model.

This led to the two-phase plan: first value classes, then specialized generics.

The Name Game: From Value Types to Value Classes

If you've read about Valhalla before and got confused by changing terminology, you're not alone. Each name change reflects a change in the model:

  • Stage 1 (early): "value types" — vague.
  • Stage 2 (2019-2020): "inline classes" — classes without identity, final by default, fields final, no synchronization. The slogan "codes like a class, works like an int" was born.
  • Stage 3 (2021): "primitive classes" with a two-projection model: a value variant (flat, non-null) and a reference variant (boxed, nullable), written as Point.val/Point.ref or Point!/Point?. Powerful but mentally heavy—programmers had to juggle two forms.
  • Stage 4 (today): "value classes" declared with the value modifier. Instances are value objects: objects without identity. A value class is still a reference type. Null-restriction is split off into a separate, optional JEP (Null-Restricted Value Class Types).

So the current JEP 401 gives us one simple concept: "does it have identity?" Nullability is orthogonal and deferred.

What You Get in JDK 28

Here's a concrete example from the JEP:

value class Point {
    private final int x;
    private final int y;
    
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
    
    // methods, validation, etc.
}

This Point behaves like a class—you can call methods, validate in constructors, use named fields—but the JVM can flatten it into a dense, inline representation. In arrays, Point[] becomes a contiguous block of x and y values, no pointers, no headers, no indirection.

Key constraints inherited from inline classes: value classes are implicitly final, fields must be final, and you cannot synchronize on a value object. These restrictions are necessary to eliminate identity.

What's Missing: Specialized Generics

The second phase of Valhalla—specialized generics (also known as "universal generics")—is not part of this JEP. The original draft was withdrawn and sent back for rework. Specialized generics would allow generics over primitives and value types, e.g., ArrayList or ArrayList. That remains a future JEP.

Why This Matters Now

For JVM developers, this is the biggest change to Java's type system since generics in JDK 5. If you write performance-sensitive code—games, graphics, databases, analytics, HPC—you can now create safe, readable types that match the speed of hand-tuned primitive arrays. The JVM will handle the flattening and layout automatically.

But don't rush to rewrite your codebase. This is a preview, disabled by default, and only the first part. Expect breaking changes in future JDKs as the rest of Valhalla lands. Start experimenting with JDK 28 early-access builds to understand the semantics and performance characteristics.

Next Steps

  • Download JDK 28 early-access builds from jdk.java.net.
  • Enable preview features with --enable-preview.
  • Try converting a small data-heavy class (like Color, Point, Complex) to a value class and benchmark.
  • Read the full JEP 401 and the companion JEP 402 (Enhanced Primitive Boxing).
  • Watch the JVM Language Summit talks by Frédéric Parain (heap flattening) and Dan Smith (object initialization).

Project Valhalla is finally here. After a decade of prototypes, name changes, and community skepticism, the first piece ships. The "they'll never ship it" crowd has lost that argument. Now the real work begins.