Valhalla: Nu bliver Java både sikrere og hurtigere
Value-klasser giver type-sikkerhed uden performance-tab
Har du nogensinde bygget domæne-modeller i Java og måttet vælge mellem sikkerhed og fart? Du ville gerne have en PositiveInt-type, så compileren kunne afvise negative værdier. Men så snart koden kom ind i en hot loop med millioner af kald, blev wrapper-objekterne en flaskehals.
Det har været en kendt begrænsning i årevis: du validerer ved API-grænsen og dropper derefter dine fine typer til fordel for primitive værdier inde i algoritmerne.
Project Valhalla ændrer den regel.
Wrapper-klasser koster
En simpel wrapper som PositiveInt fylder 16 bytes på HotSpot. Når du lægger en million af dem i et array, ligger der ikke værdier direkte i arrayet – kun references. Hver adgang kræver en pointer-dereference og øger risikoen for cache-miss.
Resultatet er fire gange så meget hukommelse som det primitive felt, det beskytter. Det er en reel begrænsning, når du skal processere data igennem hot paths.
Value-klasser løser problemet
Java 27 Early Access bringer value-keywordet med. Value-klasser har ingen identity og kan derfor behandles som primitives af JVM'en. De kan ligge flat i arrays, i object fields eller endda i CPU-registre.
public value class PositiveInt {
private final int value;
public PositiveInt(int value) {
if (value <= 0) {
throw new IllegalArgumentException("must be positive: " + value);
}
this.value = value;
}
public int value() {
return value;
}
}
Constructoren kører stadig, så validation finder sted. Men JVM'en kan nu inlinen den 4-byte int direkte uden object header eller indirection.
Flere felter, samme effekt
En Coordinate-value-klasse med både Latitude og Longitude kan nu holde to doubles contiguously – 16 bytes med zero pointers. Det sparer cache-misses i applikationer, der processerer geospatial data i stor skala.
Refined types hele vejen
Hos NameOcean ser vi allerede muligheder for DomainName og Tld value-klasser. DNS-pipelines kan nu arbejde med type-sikrede værdier uden at sacrifice performance.
public value class DomainName {
private final String value;
public DomainName(String value) {
if (!isValidDomain(value)) {
throw new IllegalArgumentException("Invalid domain: " + value);
}
this.value = value;
}
}
Compile-time korrekthed
Value-klasser bringer også F-bounded generics i spil. Med en interface som RefinedInt<T extends RefinedInt<T>> får compileren lov til at afvise, at en Probability sammenlignes med en Price. Det var tidligere praktisk umuligt, fordi wrapper overhead gjorde det fristende at droppe sådanne typer.
Hvad det betyder praktisk
- Boundary validation passer nu sammen med hot-path performance
- Type-sikkerhed skal ikke længere stoppe ved API-grænsen
- Domain-driven design kan nu være både sikker og effektiv
Project Valhalla er stadig i preview, men trenden står klar. Start allerede nu med at tænke over, hvor dine refined types kunne leve uden performance-penalty.
No more trade-off between correctness and speed.