Dev Encyclopedia
ArticlesTools

Get notified when new content drops

No spam. Just new articles, tools, and updates straight to your inbox.

Dev Encyclopedia

A reference for builders

Content

  • Articles
  • Tools
  • Contact

Connect

  • support@devencyclopedia.com
  • RSS Feed

ยฉ 2026 Dev Encyclopedia

Privacy PolicyTermsDisclaimer
  1. Home
  2. /Blog
  3. /Project Valhalla in JDK 28: What Value Classes Actually Change
java8 min read

Project Valhalla in JDK 28: What Value Classes Actually Change

JEP 401 just landed in OpenJDK mainline. Here is how to try value classes in JDK 28, what scalarization actually does, and the null surprise nobody expects.

By Dev EncyclopediaPublished June 23, 2026
On this page

On this page

  • What Actually Got Confirmed This Week
  • The Problem Valhalla Solves, in Plain Terms
  • How to Try It This Week
  • Value Class vs Record: What Is Actually Different
  • The Detail That Will Surprise You
  • What Scalarization and Heap Flattening Actually Mean
  • Migrating Existing JDK Classes
  • What Is Explicitly Not in JDK 28
  • Should You Use This Now?
  • Frequently Asked Questions

Project Valhalla has been Java's most anticipated, slowest arriving feature for over a decade. On June 15, 2026, Oracle engineer Lois Foltan confirmed the first concrete piece, JEP 401 (Value Classes and Objects), is integrating into OpenJDK's mainline this month, targeting a preview release in JDK 28. The pull request is 197,000 lines across 1,816 files. Foltan asked other OpenJDK committers to hold off on large commits during the integration window because of the scale involved.

If you have heard "Valhalla" mentioned for years without anything shipping, this is the moment something concrete actually lands. Here is what it changes, what it does not change yet, and what you can try right now.

What Actually Got Confirmed This Week

JEP 401 (Value Classes and Objects) is the first deliverable from Project Valhalla after 12 years of development. The integration into OpenJDK mainline targets a preview in JDK 28.

The scale is significant: 197,000 lines of code across 1,816 files. Oracle described it as the biggest change to Java's object model since the language's creation in 1995. Foltan explicitly asked other OpenJDK committers to pause large commits during the integration window to avoid merge conflicts at that scale.

The Problem Valhalla Solves, in Plain Terms

In Java, everything except eight primitive types (int, long, double, boolean, and the rest) is a reference type. When you write:

java
Point p = new Point(1, 2);

p is not a point. It is a pointer, a reference to an object sitting somewhere on the heap. Every time you read a field on p, the JVM has to follow that pointer first. For a single object, this overhead is invisible. For a million-element array of Point objects, you are not getting a contiguous block of coordinate data. You are getting a million pointers scattered across the heap, each requiring a separate dereference.

This is why performance-critical Java code has historically resorted to "primitive obsession" (using raw int[] arrays instead of a clean Point[] array), trading readability and type safety for the memory layout the hardware actually wants. Valhalla's stated goal, in Brian Goetz's words, is to let code "look like a class, work like an int."

How to Try It This Week

Early access builds are available now from jdk.java.net/valhalla. To enable the preview features in your own code:

bash
javac --enable-preview --release 28 Point.java
java --enable-preview Point

A minimal value class:

java โ€” Point.java
value class Point {
    int x;
    int y;

    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

And the same thing as a value record, usually the better choice when your type is genuinely just a tuple of data:

java โ€” Point.java
value record Point(int x, int y) {}

๐Ÿ’ก Testing preview features in CI

If you use GitHub Actions for your Java projects, you can pass --enable-preview as a JVM argument in your test step. See our GitHub Actions tutorial for setting up Java CI workflows.

Value Class vs Record: What Is Actually Different

Both give you generated equals(), hashCode(), and toString(). Both are immutable by convention. The real distinction is about identity.

A value class gives up object identity entirely. Instances are compared by their component values, not by reference. Calling synchronized on a value class instance now throws an exception, because synchronization fundamentally requires identity.

In exchange for giving up identity, you get the JVM's freedom to optimize. A reference type has to support == reference comparison and locking, which means the JVM cannot safely flatten it into a register or an array slot. It has to maintain that pointer. A value class makes no such promise, so the JVM is free to scalarize or flatten it.

Value ClassRecord
Generated equals/hashCode/toStringYesYes
Immutable fieldsYes (implicit)Yes (implicit)
Object identityNo (given up)Yes (retained)
synchronized allowedNo (throws exception)Yes
JVM can scalarize/flattenYesNo
Can be a value recordYes (value record)Yes (value record)

The Detail That Will Surprise You

Here is the part everyone gets wrong on first read: value classes can still be null.

java
Point p = null; // perfectly legal in JDK 28's value class model

"Value type" intuitively sounds like "works like a primitive, so no null," but that is a separate, later JEP. Non null types are not part of JDK 28. In this preview, value classes are still reference types under the hood; they have just given up identity, not nullability.

Do not write code assuming a value class field can never be null until that separate JEP lands.

โš  Null is still allowed

Value classes in JDK 28 are reference types that gave up identity, not nullability. Non nullable (null restricted) types are a separate, future JEP. Do not assume your value class fields cannot be null.

Java type categories after JEP 401. Value classes sit between primitives and regular objects.
Type categoryIdentityNullableJDK 28 status
Primitives (int, long, etc.)NoNoUnchanged
Value classes (new)NoYesPreview in JDK 28
Regular classes (Object, etc.)YesYesUnchanged
Non null value types (future)NoNoNot in JDK 28

What Scalarization and Heap Flattening Actually Mean

Take a Color value class with three byte fields for red, green, and blue. Without Valhalla, passing a Color to a method means passing a pointer to a heap-allocated object: an allocation, a pointer dereference, and GC pressure for an object that is conceptually just three bytes.

With scalarization, when the JIT compiler can prove the concrete type at a call site, it breaks the value object down into its constituent fields at the machine code level. Instead of passing a pointer to a Color, it passes three bytes plus a null flag directly. No allocation happened. There is nothing for the garbage collector to track.

Heap flattening handles the array case: instead of an array of pointers to separately allocated Color objects scattered across the heap, the array stores the actual byte data inline, contiguously. That is the layout you would get from a hand-rolled byte[] encoding, but with a real class, real field names, real validation in the constructor, and real methods. For applications that rely on caching strategies for performance, eliminating object overhead at the memory level is a complementary optimization.

โ„น Known limitation

Scalarization typically does not work when a variable's static type is a supertype of the value class (like Object, or an erased generic type parameter). This is a known, current limitation of the JDK 28 preview, not a bug to report.

๐Ÿ’ก Try it on your own class

See exactly how much memory a value class would save your own class with JavaObjectLayoutCalc. Describe your fields, and get the byte-level comparison instantly.

Migrating Existing JDK Classes

java.lang.Integer and other primitive wrapper classes are migrating to value classes under this preview. This is where Goetz's warning about breaking changes becomes concrete: code that calls synchronized on Integer objects now fails with an exception.

If you have code anywhere that does synchronized(someInteger) { ... }, a pattern most developers do not realize they rely on until it breaks, this preview will surface it immediately. Search your codebase for synchronized blocks on wrapper types before enabling the preview.

๐Ÿšซ Breaking change under preview

With the preview enabled, synchronized(someInteger) throws an exception. Audit your codebase for synchronized blocks on Integer, Long, Double, and other wrapper types before opting in.

What Is Explicitly Not in JDK 28

Goetz has been direct about scope: "this is just the first part of Valhalla." The following features are not included in JDK 28:

  • Null restricted (non nullable) types are a separate JEP, not part of this preview
  • Full specialized generics (List<int>) are not available yet
  • 128 bit value encodings are not supported
  • Vector API remains in incubation (it depends on Valhalla's underlying VM primitives landing first)

JDK 28 itself is not a Long Term Support release. That is expected to be JDK 29 in September 2027, and Goetz has cautioned that hoping for Valhalla to fully exit preview by then is "optimistic."

Should You Use This Now?

It is a preview feature, disabled by default, and the syntax can still change release to release based on feedback, which is the entire point of shipping it as a preview rather than a finished feature.

If you work on performance-critical Java (data processing, numerics, game engines, anything currently fighting object overhead with hand-rolled primitive encodings), this is worth experimenting with now and reporting real-world findings to the valhalla-dev mailing list. It is not yet something to migrate production code onto. The team explicitly wants feedback from real applications before the design settles further. If you are planning a migration, the experience is similar to how teams approached the TypeScript 7 migration: experiment in a branch, benchmark, and wait for stability before committing production code.

๐Ÿ’ก Best use of the preview period

Try converting one performance-sensitive data class to a value class in a branch. Benchmark it against the reference type version. Report your findings to valhalla-dev@openjdk.org, which is exactly the kind of feedback that shapes future JDK releases.

Frequently Asked Questions

What is Project Valhalla?

Project Valhalla is a long-running OpenJDK initiative to redesign Java's type system so that user-defined types can behave like primitives at the JVM level. Its goal is to eliminate the performance overhead of heap allocation and pointer indirection for small, immutable data types, while keeping the expressiveness of classes. The phrase Brian Goetz uses is "codes like a class, works like an int."

The first concrete deliverable is JEP 401 (Value Classes and Objects), which entered preview in JDK 28 in June 2026 after more than 12 years of design work.

Can value classes be null in Java?

Yes. In the JDK 28 preview, value classes are still reference types. They have given up object identity (no reliable == reference comparison, no synchronized) but they remain nullable. Writing Point p = null; is perfectly legal.

Non nullable (null restricted) types are planned as a separate, later JEP and are not part of JDK 28.

What is the difference between a value class and a record in Java?

Both are immutable and generate equals(), hashCode(), and toString(). The key difference is identity: a record retains object identity (you can synchronize on it, == tests reference equality), while a value class surrenders identity entirely. Giving up identity is what lets the JVM scalarize and flatten value classes for better performance.

You can combine both: a value record is a record that also gives up identity. For pure data carriers, value record Point(int x, int y) {} is usually the most concise option.

How do I enable Valhalla preview features in JDK 28?

Download an early access build from jdk.java.net/valhalla, then compile and run with the --enable-preview flag:

bash
javac --enable-preview --release 28 YourFile.java
java --enable-preview YourFile

For Maven or Gradle projects, add the --enable-preview flag to both the compiler and the JVM arguments in your build configuration.

When will Project Valhalla be stable and out of preview?

There is no confirmed timeline. JDK 28 ships the first preview of JEP 401 (value classes). The next Long Term Support release is expected to be JDK 29 in September 2027, but Brian Goetz has described hoping for Valhalla to fully exit preview by then as "optimistic."

The broader Valhalla roadmap includes additional JEPs (null restricted types, specialized generics) that have not yet entered preview. Full completion will span multiple JDK releases.

How much faster are value classes compared to regular Java objects?

The performance benefit depends on your workload and how the JIT compiler optimizes your specific code. The two main optimizations are scalarization (breaking a value object into its component fields, eliminating heap allocation entirely) and heap flattening (storing values inline in arrays instead of as pointers to separate objects).

For data-heavy applications that process large arrays of small objects (coordinates, colors, timestamps), the improvement can be substantial because you eliminate millions of pointer dereferences and reduce GC pressure. For code that mostly works with single instances, the difference will be minimal.

Related Articles

devops

GitHub Actions Tutorial: CI/CD from Push to Deploy (2026)

Learn GitHub Actions: write your first workflow, run tests automatically, use secrets safely, deploy via SSH, cache dependencies, and run matrix builds.

Jun 12, 2026ยท13 min read
security

GitHub Actions Security: 7 Misconfigurations to Avoid

The 7 GitHub Actions misconfigurations behind real supply chain attacks: weak GITHUB_TOKEN scope, pull_request_target, unpinned actions, script injection.

Jun 12, 2026ยท14 min read

On this page

  • What Actually Got Confirmed This Week
  • The Problem Valhalla Solves, in Plain Terms
  • How to Try It This Week
  • Value Class vs Record: What Is Actually Different
  • The Detail That Will Surprise You
  • What Scalarization and Heap Flattening Actually Mean
  • Migrating Existing JDK Classes
  • What Is Explicitly Not in JDK 28
  • Should You Use This Now?
  • Frequently Asked Questions
Advertisement