Modern Java

49. Value Classes (Project Valhalla)

Value classes (Project Valhalla, value class) are identity-free objects whose instances can be flattened in memory like primitives โ€” eliminating heap allocation overhead for small, immutable data types.

Java 23+ (preview; evolving through Java 25)

Explanation

Today, every object in Java has an identity (memory address), even a Point(int, int) that is logically just two integers. This identity forces heap allocation, pointer indirection, and GC overhead. Project Valhalla addresses this with value classes (and eventually primitive types).

A value class declaration removes the identity: you cannot use == to compare instances (only equals()), cannot synchronise on them, and cannot use them as null by default (though nullable flavours are planned). In return, the JVM can store them inline โ€” a Point[] array can be a flat array of integers in memory, not an array of pointers.

As of Java 23โ€“25 (the feature is still evolving), the preview syntax uses value class. Records automatically become value types in a future JVM. The headline benefit: dramatically reduced GC pressure for data-intensive workloads (games, scientific computing, financial applications).

Example

// Note: value classes require --enable-preview in Java 23-25
// This example illustrates the concept; run with:
//   java --enable-preview --source 23 ValueClassesDemo.java

public class ValueClassesDemo {
    // value class: identity-free, no heap object in arrays
    value class Point {
        int x;
        int y;

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

        double distanceTo(Point other) {
            int dx = this.x - other.x, dy = this.y - other.y;
            return Math.sqrt(dx * dx + dy * dy);
        }

        @Override public String toString() { return "(" + x + ", " + y + ")"; }
    }

    public static void main(String[] args) {
        Point p1 = new Point(0, 0);
        Point p2 = new Point(3, 4);

        // No identity โ€” cannot use == (only equals)
        System.out.println(p1.distanceTo(p2)); // 5.0

        // In arrays: JVM can flatten these to int pairs โ€” no pointer indirection
        Point[] points = new Point[1000];
        for (int i = 0; i < points.length; i++) {
            points[i] = new Point(i, i * 2);
        }
        System.out.println("First: " + points[0] + " Last: " + points[999]);
    }
}

Sources