Project Valhalla: Value Classes und was sie für Java bedeuten

Einführung

Project Valhalla ist eines der am längsten laufenden OpenJDK-Projekte. Nach über zehn Jahren Entwicklung gibt es jetzt konkrete Fortschritte: mit JEP 401 (Value Classes and Objects) liegt ein Early-Access-Build auf Basis von JDK 27 vor. Die Grundidee ist einfach, aber die Auswirkungen auf die Java-Plattform sind gravierend: Objekte, die sich wie primitive Typen verhalten.

Das Problem

In Java gibt es zwei Arten von Typen: Primitive (int, double, boolean) und Referenztypen (alles andere). Primitive sind schnell und effizient im Speicher, unterstützen aber keine Methoden, kein Null und keine Vererbung. Referenztypen haben all das, aber jeder Zugriff geht über eine Referenz im Heap — das kostet Speicher (Header) und Performance (Pointer-Dereferenzierung, Cache-Misses).

// Primitive: 8 Bytes, direkt im Speicher, kein Overhead
int x = 42;

// Referenztyp: 16 Bytes Header + 8 Bytes Referenz = 24 Bytes pro Objekt
// Plus Pointer-Indirektion bei jedem Zugriff
Point p = new Point(1, 2);

Für Datenmodelle wie Punkte, komplexe Zahlen,货币werte oder Temperaturwerte ist das ineffizient. Du willst die Abstraktion eines Objekts, aber die Performance eines primitiven Typs.

Value Classes: Codes like a class, works like an int

Value Classes lösen dieses Problem. Ein Value Class wird mit dem value-Modifier deklariert:

public value class Point {
    private final double x;
    private final double y;
    
    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }
    
    public double distanceTo(Point other) {
        double dx = this.x - other.x;
        double dy = this.y - other.y;
        return Math.sqrt(dx * dx + dy * dy);
    }
}

Die Regeln: nur final-Felder, keine Objekt-Identität. Zwei Value Objects sind gleich, wenn alle Felder gleich sind. Vergleichbar mit Records, aber mit Laufzeit-Optimierungen durch die JVM.

Laufzeit-Optimierungen

Das Besondere an Value Objects sind die JIT-Optimierungen:

Heap Flattening

Value Objects, die als Felder oder Array-Elemente gespeichert werden, werden direkt inline im Speicher abgelegt — ohne separate Objekt-Allocierung und ohne Pointer.

// Ohne Value Classes: Array von Point-Referenzen
Point[] points = new Point[1000]; // 1000 Referenzen + 1000 separate Objekte

// Mit Value Classes: Array mit flachen Point-Daten
value Point[] points = new value Point[1000]; // Daten liegen direkt hintereinander

Das verbessert die Cache-Lokalität deutlich und reduziert den Speicherverbrauch.

Scalarization

Wenn ein Value Object in einem Hot Path genutzt wird, kann der JIT Compiler es komplett eliminieren und die Feldwerte direkt in Registern halten. Keine Objekt-Allocierung, kein GC-Druck.

Was bedeutet “keine Objekt-Identität”?

Value Objects haben keine Identität im Sinne von ==. Es gibt keine Monitor-Operationen (synchronized, wait, notify), und sie können nicht als Lock verwendet werden. Zwei Value Objects mit gleichen Feldwerten sind nicht unterscheidbar:

value Point a = new Point(1.0, 2.0);
value Point b = new Point(1.0, 2.0);

// a == b ist undefiniert (keine Identität)
// a.equals(b) vergleicht die Feldwerte → true

Das ist analog zu primitiven Typen: zwei int-Variablen mit Wert 42 sind ebenfalls nicht “identisch”.

Kompatibilität und Migration

Die JEP 401 Early-Access-Builds sind auf jdk.java.net/valhalla verfügbar. Wer experimentieren will:

  • Java-Code mit value-Modifier kompilieren: javac --enable-preview
  • Ausführen: java --enable-preview
  • Bestmögliche Performance: alle Klassen, die Value Classes referenzieren, mit --enable-preview kompilieren

Bekannte Einschränkungen:

  • java.io.Serializable funktioniert noch nicht vollständig mit Value Objects
  • Reflection (Field.setAccessible) hat Einschränkungen
  • Generische APIs mit polymorphen Variablen können nicht voll optimiert werden

Was Value Classes für bestehenden Code bedeuten

Viele bestehende Klassen lassen sich potenziell zu Value Classes migrieren: java.awt.Point, java.time.LocalDate, java.util.Optional, Records ohne Identity. Die Migration ist oft kompatibel, aber es gibt Verhaltensänderungen bei ==, synchronized und Serialisierung, die beachtet werden müssen.

Ausblick

Value Classes werden voraussichtlich als Preview in JDK 27 erscheinen. Die finale Version wird davon abhängen, wie das Feedback aus den Early-Access-Builds ausfällt. Bis dahin gilt: ausprobieren, Feedback geben, und die Entwicklung beobachten.

Die Vector API (aktuell 11. Inkubation) wartet ebenfalls auf Value Classes, da sie von den Performance-Eigenschaften profitieren wird. Valhalla ist der Schlüssel für mehrere langfristige Java-Verbesserungen.

Fazit

Value Classes sind eine der wichtigsten Änderungen an der Java-Plattform seit Generics. Sie schließen die Lücke zwischen primitiven Typen und Objekten und ermöglichen effiziente Datenmodellierung ohne den Overhead von Referenztypen. Wer datenintensive Anwendungen schreibt, sollte die Early-Access-Builds jetzt testen und Feedback an das Valhalla-Team senden.