Share
Will Valhalla Fix Tony’s Billion $ Mistake?
In March 2027, in JDK 28 (JVM gods willing!), after more than 12 years of effort, the Valhalla project will deliver its first feature: Value Classes (JEP 401) as a preview feature. Value classes are defined as regular classes with a "value" keyword in front. They are backward compatible with your code written before Java 28, without you having to recompile it.
Value classes bring new optimization opportunities at the JVM level: scalarization on stack and flattening on heap. For that, the Java specification had to be reinterpreted and enhanced, challenging us to reconsider some of the fundamentals on which Java was created 30 years ago. What does == mean? Is a reference always a pointer? Can an instance of a value class be null? Can you observe the transition between the default values and the final values of fields during object construction? And more.
This presentation covers all these questions, showing the trade-offs that need to be made in order to bring value classes to the Java platform.
You will hear about new code patterns, performance, and type safety. And, as value classes are just the first step, we will cover what Valhalla should bring in the future.
José
Transcript
110 slides
-
Will Valhalla Fix Tony’s Billion $ Mistake? Exploring New Ways
to Manage Your In Memory Data José Paumard Java Developer Advocate Java Platform Group Rémi Forax Associate Professor Université Gustave Eiffel -
https://twitter.com/Nope! https://github.com/forax https://speakerdeck.com/forax OpenJDK, ASM, Tatoo, Pro, etc… One of
the fathers of invokedynamic (Java 7) Lambda (Java 8), Module (Java 9) Constant dynamic (Java 11) Record, Pattern Matching (Java 17 / 21) Valhalla (Java 28+) -
Tony Hoare’s 1B$ mistake Null reference violations have cost in
terms of programmer time, user discomfort and general damage in the order of a billion $. Tony Hoare, QCon London, 2009 4 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Tune in! Inside Java Newscast Inside.java JEP Café 6 Inside
Java Podcast Road To 25 series Java 27 Launch Cracking the Java coding interview Copyright © 2026, Oracle and/or its affiliates 10/4/2026 Sip of Java -
OpenJDK is the place where it all happens https://openjdk.org/ 7
Copyright © 2026, Oracle and/or its affiliates | https://openjdk.org/projects/Valhalla/ 10/4/2026 -
OpenJDK is the place where it all happens https://jdk.java.net/ 8
Copyright © 2026, Oracle and/or its affiliates 10/4/2026 -
OpenJDK is the place where it all happens https://jdk.java.net/28/ 9
Copyright © 2026, Oracle and/or its affiliates 10/4/2026 -
OpenJDK is the place where it all happens Prefer the
JDK 28 EA version https://jdk.java.net/ 10 Copyright © 2026, Oracle and/or its affiliates 10/4/2026 -
OpenJDK is the place where it all happens https://openjdk.org/jeps/401 11
Copyright © 2026, Oracle and/or its affiliates 10/4/2026 -
OpenJDK is the place where it all happens https://openjdk.org/jeps/539 12
Copyright © 2026, Oracle and/or its affiliates 10/4/2026 -
The Valhalla Project OpenJDK project lead by Brian Goetz https://openjdk.org/projects/valhalla/
Started on July, 2014! Brian Goetz 13 Copyright © 2026, Oracle and/or its affiliates | Dan Smith 10/4/2026 John Rose -
Primitive vs. Object in Java Strong separation between primitives and
Objects Java code uses primitives directly (CPU and GPU friendly) and uses Objects through references Primitives are not part of the Object Oriented Programming world (no encapsulation, no abstraction) 14 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Valhalla / JEP 401 Bring the benefits of primitives to
objects and classes Enable flatter and denser memory layouts Enable adding new primitive-like classes Compatible migration of existing value-based classes Healing the reference-primitive divide Enable runtime specialization of generics 15 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
JEP 401 Pull Request 16 Copyright © 2026, Oracle and/or
its affiliates | 10/4/2026 -
JEP 401 Pull Request Friday 9th 9:30 – 10:20 Room
6 17 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Valhalla 1) What does it mean to lack identity? What
is object identity? How does it relate to mutability? 2) How can you improve performance? 3) How can you save memory with value objects? 19 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
What is Object Identity and How Does it Relate to
Mutability? 20 Copyright © 2026, Oracle and/or its affiliates 10/4/2026 -
What is Object Identity? The identity of an object is
its address in memory record Song( String title, short duration) {} OxFF238E64 OxFF239A24 Song String title hashCode beatIt 1430316469 var beatIt = new Song("Beat it", 256); value duration 256 OxFF14C874 B 21 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 e a t i t -
What is Object Identity? There can only be one copy
of any object in memory OxFF148F32 playList class PlayList { String title; ArrayList<Song> songs; // constructors and methods } var playList = new PlayList("80s"); playList.add(beatIt); playList.add(thriller); playList.add(billieJean); PlayList String title hashCode 55419 songs value OxFF238E64 Copyright © 2026, Oracle and/or its affiliates | OxFF18A060 ArrayList size 3 elementData 22 OxFF564FA4 10/4/2026 8 OxFF024594 0 s -
What is Object Identity? There can only be one copy
of any object in memory OxFF148F32 playList class PlayList { String title; ArrayList<Song> songs; // constructors and methods } var playList = new PlayList("80s"); playList.add(beatIt); playList.add(thriller); playList.add(billieJean); PlayList String title hashCode 55419 songs value OxFF238E64 Copyright © 2026, Oracle and/or its affiliates | OxFF18A060 ArrayList size 3 This allows for mutable objects elementData 23 OxFF564FA4 10/4/2026 8 OxFF024594 0 s -
Memory Layout of an Identity Object record Song(String title, short
duration) {} Header 64 bits title 32 (64) bits duration padding 16 bits 16 (48) bits The header carries the following information: - Class pointer - GC info - Locking - Object’s stable identity hash code - Bits for Valhalla JEP 450: https://openjdk.org/jeps/450 24 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
What is an Object without Identity? The identity of an
object is its address in memory No identity means no address, thus no mutability All the fields and class itself are final An object without identity behaves like a primitive value 3 is the size of the list it is 3, wherever it lives in memory 25 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Value Objects vs. Identity Objects 1) A value class is
a class whose instances do not have identity 2) These instances are called value objects 3) A non-value class is called an identity class You want the best of both worlds! - Abstraction offered by classes - Performance offered by primitives 26 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Value Objects value class Song { String title; short duration;
// constructors, methods } value record Song(String title, short duration) {} var beatIt = new Song("Beat it", 256); 27 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Value Objects Since value objects give up their identity, the
JVM can use the value objects directly (no pointer) Two consequences: 1) No object header for value objects 2) You need to reinterpret address-based operations 28 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Demo 1) Création d’un value record 2) Différence de sémantique
avec == sur une value class 3) Hashcode sur une value class 4) Synchronization 5) Weak reference 30 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Object Mutation in Constructors Problem: you can observe field mutation
during object construction class Song { String title; Song(String title) { IO.println("Title: " + this); this.title = title; } public String toString() { return this.title; } } > var song = new Song("Beat it"); Title: null 31 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Demo Strict initialization 1) Classe normale avec appel à super
en premier, qui montre la mutation d’un champ final 2) Ne compile plus si l’on met value 3) Montrer comment mettre le super à la fin règle les problèmes, le print après l’appel à super() 33 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Object Mutation in Constructors Value objects have strict fields, their
mutation cannot be observed value class Song { String title; Song(String title) { IO.println("Title: " + this); this.title = title; } public String toString() { return this.title; } } Cannot reference 'this' before superclass constructor is called 34 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Object Mutation in Constructors Reason: in value classes, the call
to super() is added at the end of the constructor by the compiler value class Song { String title; Song(String title) { IO.println("Title: " + this); this.title = title; super(); } } 35 Copyright © 2026, Oracle and/or its affiliates | public String toString() { return this.title; } Cannot reference 'this' before superclass constructor is called 10/4/2026 -
Object Mutation in Constructors Reason: in value classes, strict fields
must be initialized before the call to super() value class Song { String title; Song(String title) { super(); this.title = title; } public String toString() { return this.title; } } strict field title is not initialized before the supertype constructor has been called 36 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Object Mutation in Constructors 1) Strict fields must be initialized
before the call to super() 2) You can use this after the call to super() value class Song { String title; Song(String title) { this.title = title; super(); IO.println("Title: " + this); } public String toString() { return this.title; } } > var song = new Song("Beat it"); Title: Beat it 37 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Value Class Strict Initialization Rules A value class has strict-init
fields They must be initialized before the call to super() If super() is not called explicitly, the compiler adds it at the end of the constructor 38 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
JEP 539: Strict Field Initialization https://openjdk.org/jeps/539 39 Copyright © 2026,
Oracle and/or its affiliates 10/4/2026 -
JEP 513: Flexible Constructor Bodies https://openjdk.org/jeps/513/ 40 Copyright © 2026,
Oracle and/or its affiliates 10/4/2026 -
Demo 1) Mot-clé value sur une classe abstraite 42 Copyright
© 2026, Oracle and/or its affiliates | 10/4/2026 -
Abstract Class? A value class can only extend an abstract
value class or Object abstract class AbstractTitle { value class Song extends AbstractTitle { String title; AbstractTitle(String title) { this.title = title; super(); } Song(String title) { super(title); } } Value classes may only extend abstract value classes or 'java.lang.Object' public String title() { return title; } } 43 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Abstract Class? A value class can only extend an abstract
value class or Object value abstract class AbstractTitle { value class Song extends AbstractTitle { String title; AbstractTitle(String title) { this.title = title; super(); } Song(String title) { super(title); } } public String title() { return title; } } 44 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Abstract Class? On the other hand, any class can extend
abstract value class value abstract class AbstractTitle { class Song extends AbstractTitle { String title; AbstractTitle(String title) { this.title = title; super(); } Song(String title) { super(title); } } public String title() { return title; } } 45 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Abstract Value Classes Two rules for abstract classes: 1) An
identity class can extend an abstract value class 2) A value class can only extend an abstract value class (or Object) The value keyword for abstract classes means valueenabled, this class respects the strict initialization rules 46 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Improving Performance: Scalarization on Stack 47 Copyright © 2026, Oracle
and/or its affiliates 10/4/2026 -
Benchmarks: Let’s Make a Mixtape! Let us run some code
and see the performance improvements And create Mixtapes from songs and playlists © Let’s Make a Mixtape https://www.letsmixtape.com/ 48 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Benchmarks value record ValueSong(String title, short duration) {} value record
ValuePlayList(String title, ValueSong[] songs) { ValuePlayList { Objects.requireNonNull(title); songs = songs.clone(); // defensive copy } public ValueSong[] songs() { return songs.clone(); // defensive copy } } 49 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Benchmarks value record ValueSong(String title, short duration) {} value record
ValuePlayList(String title, ValueSong[] songs) {} record IdentitySong(String title, short duration) {} record IdentityPlayList(String title, IdentitySong[] songs) {} 50 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Benchmarks – Creating a MixTape V1 Adding the durations of
the songs to create a mixtape V1: summing durations as shorts Song mixTapePrimitive(PlayList playList) { var duration = (short) 0; Songs are read from an array No object creation Sum of shorts in a loop for (var i = 0; i < playList.songs.length; i++) { duration += playList.songs.get(i).duration(); } return new Song(playList.title, duration); } 51 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Benchmarks – Creating a MixTape V2 Adding the durations of
the songs to create a mixtape V2: adding songs Song mixTapeObject(PlayList playList) { var song = new Song(playList.title, (short) 0); for (var i = 0; i < playList.songs.length; i++) { song = new Song(song.title(), (short) (song.duration() + playList.songs[i].duration())); } Songs are read from an array A new Song is created in each iteration Durations are added one by one return song; } 52 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Benchmarks – Creating a MixTape V3 Adding the durations of
the songs to create a mixtape V3: reducing a stream of songs Song mixTapeReduce(PlayList playList) { Songs are read from an array The calculation is a stream reduction return Arrays.stream(playList.songs).reduce( new Song(playList.title, (short) 0), (s1, s2) -> new Song(s1.title(), (short) (s1.duration() + s2.duration()))); } 53 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Benchmarks – Results Results for Identity Classes Perf. MixTape 100
songs MixTape 100 songs MixTape 100 songs [V1 – Primitive] [V2 – Object] [V3 – Stream] Score Error 33 ± 0.2 190 ± 2.6 191 ± 0.8 Units ns/op ns/op ns/op Results for Value Classes, no array flattening Perf. MixTape 100 songs MixTape 100 songs MixTape 100 songs 54 Copyright © 2026, Oracle and/or its affiliates | [V1 – Primitive] [V2 – Object] [V3 – Stream] Score Error 33 ± 0.69 33 ± 0.53 196 ± 1.76 10/4/2026 Units ns/op ns/op ns/op -
Benchmarks – GC Count and Time Results for Identity Classes
Perf. Creating a MixTape [V1 – Primitive] Creating a MixTape [V2 – Object] Creating a MixTape [V3 – Stream] Score Units 70 count 138 count 122 count Score Units 43 ms 110 ms 93 ms Score Units 0 count 0 count 19 count Score 0 0 16 Results for Value Classes Perf. Creating a MixTape [V1 – Primitive] Creating a MixTape [V2 – Object] Creating a MixTape [V3 – Stream] 55 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 Units ms ms ms -
Scalarization on Stack So your source code: Song createMixTape(PlayList playList)
{ var song = new Song(playList.title, (short) 0); for (var i = 0; i < playList.songs.length; i++) { song = new Song(song.title, (short) (song.duration() + playList.songs[i].duration())); } return song; } 56 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Scalarization on Stack Is executed in that way at the
assembly level (JIT) (String, short) createMixTape(PlayList playList) { var song = (playList.title, (short) 0); for (var i = 0; i < playList.songs.length; i++) { song = (song.title, song.duration + playList.songs[i].duration); } return (song.title, song.duration); } (this pseudo code, not Java) 57 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Scalarization on Stack How is the code optimized? Objects are
scattered as values Only the values of their fields are passed, as 1) The parameters and the returned object are stored in registers 2) Local variables and fields are stored in registers 58 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Why Does Not It Work with Streams? Short answer: because
of type erasure The VM sees a stream of objects, not a Stream<Song>, so the value type nature of Song is not seen and cannot be used We need specialized generics for that, and we are not there yet 59 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Saving Memory: Flattening on Heap 61 Copyright © 2026, Oracle
and/or its affiliates 10/4/2026 -
What is Flattening? length Song[] songs Header If Song is
an identity class An array of Song is an array of pointers Song String title hashCode 1430316469 duration 256 62 Copyright © 2026, Oracle and/or its affiliates | value 10/4/2026 B e a t i t -
What is Flattening? 1 title duration 249 1 title duration
278 String hashCode 1430316469 B e a value 63 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 t i t padding duration 256 padding title padding length Song[] songs Header For Value Objects, flattening consists in encoding the values instead of pointing to the memory location 1 -
What is Flattening? 1 title duration 256 1 title duration
256 padding duration 256 padding title padding length Song[] songs Header For Value Objects, flattening consists in encoding the values instead of pointing to the memory location 1 An extra 8 bits information tells if the flattened reference is null or not: null_marker It is still a big memory saving! 64 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Constraints on Flattening There is a limitation on the size
of the objects you can flatten Null references → you need a 8 bits marker Atomically → maximum size of 64 bits That leaves 56 bits for your value object 65 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Constraints on Flattening value record ValueSong(String title, int duration) {}
// No flattening for you! The Song value object is 32 bits + 32 bits So it cannot be flattened 66 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Constraints on Flattening value record ValueSong(String title, int duration) {}
// No flattening for you! The Song value object is 32 bits + 32 bits So it cannot be flattened 67 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Benchmarks – Results Results for Value Classes, no array flattening
Perf. MixTape 100 songs MixTape 100 songs MixTape 100 songs [V1 – Primitive] [V2 – Object] [V3 – Stream] Score Error 33 ± 0.69 33 ± 0.53 196 ± 1.76 Units ns/op ns/op ns/op Results for Value Classes, with array flattening Perf. MixTape 100 songs MixTape 100 songs MixTape 100 songs 68 Copyright © 2026, Oracle and/or its affiliates | [V1 – Primitive] [V2 – Object] [V3 – Stream] Score Error 49 ± 0.2 53 ± 0.2 2611 ± 25.5 10/4/2026 Units ns/op ns/op ns/op -
Value Object Decoding songs[1] title duration 256 0 padding A
value object from an array needs to be decoded using shift and mask var song = song[i] var null_marker = song & 0xFF var title = song >>> 32 var duration = (song >>> 16) & 0xFFFF Usually, those operations are fast and the RAM access is slow Microbenchmark magnified them because the array is in the caches 69 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Benchmarks – Results Results for non-flattened vs. flattened Value classes
100 songs 1_000 songs 10_000 songs 100_000 songs 1_000_000 songs Score Error 33 ± 0.3 421 ± 1.8 4.32 ± 0.11 79.9 ± 4.2 2.71 ± 0.14 Value classes flattened 100 songs 1_000 songs 10_000 songs 100_000 songs 1_000_000 songs 70 Copyright © 2026, Oracle and/or its affiliates | Score Error 54 ± 0.5 502 ± 3.3 5.24 ± 0.05 51.3 ± 0.33 507 ± 7.0 10/4/2026 Units ns/op ns/op s/op s/op ms/op Units ns/op ns/op s/op s/op s/op -
Benefits of Flattening 1) Denser storage 2) No extra pointer
dereferencing 3) Localized storage so no pointer chasing The last two points are hard to see because Java GCs are moving collectors, so they already group objects together 71 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
How Does it Work Under the Hood? 72 Copyright ©
2026, Oracle and/or its affiliates 10/4/2026 -
Observing a "Real Application" Let us use JFR to see
what is happening during the benchmark Identity objects: almost 2GB of Song objects are created 73 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Observing a "Real Application" Let us use JFR to see
what is happening during the benchmark Value objects: less than 3MB of Song objects are created 74 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Observing a "Real Application" Here are the total allocations for
Song[] and Song 75 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Value Class is a HotSpot Optimization Value classes are managed
using pointers in the interpreter The JIT (C1, C2) remove allocation and indirection when the bytecode is tranformed to machine code Same bytecode when using an identity class or a value class 76 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Java Compiler and VM (JEP 539) When compiling a value
class - The compiler clears the ACC_IDENTITY modifier bit of the class file - The compiler sets ACC_STRICT_INIT on all fields 77 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
JVM Strategy for Loading Classes In Java classes are loaded
lazily A class is not loaded when referenced as a field type To trigger field flattening optimizations, the JVM needs to know if a given field type is a value class So it needs to load the value classes earlier 78 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Java Compiler and VM (JEP 539) When compiling a class
that uses value classes the compiler inserts an attribute LoadableDescriptors that lists the classes that should be pre-loaded The VM loads these classes early to check if they are value classes 79 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
JDK Classes Retrofitted as Value Classes Most existing classes annotated
with @ValueBased are now value classes - Optional and most classes of java.time - all wrappers Boolean, Integer, etc… 80 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
JDK Classes Retrofitted as Value Classes This may break some
existing code as @ValueBased contract was not enforced before var key = new Integer(32); synchronized(key) { // breaks with JDK 28 --enable-preview } But who would be foolish enough to do that? 81 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Preparing Your Code for JEP 401 You can already -
use flexible constructor (JEP 513) to write super() call at the end of the constructor - do not use == on objects, even when overriding equals() - do not synchronize on something you do not own - do not create a WeakReference on something you do not own 82 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Value Classes Wrap up Mantra: code like a class, works
like an int - Scalarization is done by the JIT - Flattening if payload size is less than 56 bits - No need to recompile your application (almost true!) - Retrofit Optional, LocalDate, Integer, Double 83 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Challenges 1) How to improve heap flattening? 2) How to
create user-defined primitive types? 85 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Field Flattening Currently HotSpot supports four kinds of field and
array flat layout atomic non_atomic 86 Copyright © 2026, Oracle and/or its affiliates | null_marker null_free Limited to 56 bits Limited to 64 bits Must be strict final No restriction 10/4/2026 -
How to Improve Heap Flattening? How to add information about
- nullability? - atomicity? Non-atomic read only fields and array elements support nullable Non-atomic read/write fields and array elements are also null-restricted 87 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Exploration 1: Null-Restricted Types Let's help flattening by adding nullability
markers - ! or ? sigils at the end of a type - ! for strictness/certainty - ? for uncertainty: Boolean!, Optional!, Complex?, etc 88 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Bang ! As a Contract Extends Java to add !
at the end of a type of a field value record Song(String title, short duration) {} Song! means that this field cannot be null value record GrammyAward(Song! song, short year) {} 89 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Bang ! As a Contract A null-restricted field cannot be
set to null value record Song(String title, short duration) {} value class GrammyAward { private Song! song; private short year; GrammyAward(Song song, short year) { this.song = song; // the VM can throw a NullPointerException here this.year = year; super(); } } 90 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Using ? Instead of ! Like in Kotlin: String s
= null; // Not valid in Kotlin, valid in Java Adding ? requires to change the semantics of Java This is not a backward compatible change 91 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Using ! on Parameters with Identity Objects value record Song(String!
title, int duration) {} // fits in 64 bits! value record GrammyAward(Song! song, short year) {} static boolean isGrammy(List<GrammyAward> grammyAwards, Song! song) { return grammyAwards.stream() .anyMatch(grammyAward -> grammyAward.song().equals(song)); } This is equivalent to Objects.requireNonNull() on the parameter 92 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Creating an Array with ! The array cannot be initialized
to null var songs = new Song![4]; // does not compile You need a special syntax var songs = new Song![4] {index -> new Song(DEFAULT_TITLE, DEFAULT_DURATION); 93 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Method Selection and ! Because of backward compatibility, ! cannot
be used in method selection class Player { void play(Object o) {} } class MusicPlayer extends Player { void play(Song! c) {} } MusicPlayer player = new MusicPlayer(); player.play(null); Which method is called: Player.play() or MusicPlayer.play()? 94 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Is Declaring ! at Type Level a Good Idea? null-restricted
or non-atomic look more like storage keywords than markers on types Also those keywords are implementation decisions, not something the user should control The result of the exploration is: ! will not be introduced for value classes 95 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Exploration 2: Primitive Classes A primitive class is a value
class that acts like a primitive /* primitive */ record Complex(double re, double im) {} class Holder { Complex complex; // null-restricted Holder() { // this.complex is initialized with Complex(0d, 0d) } } 96 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Primitive Classes A primitive class is a value class that
acts like a primitive - Non-atomic on heap, like primitives (full flattening) - Non-null on heap, like primitives - Have a default value on heap, like primitives 97 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Giving Up Encapsulation A primitive class → no identity, no
encapsulation Fields are all independent → no way to enforce invariants on fields A primitive class is a compound of all its fields 98 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Default Value The default value is only used for fields,
like primitives class Holder { Complex complexField; // set to the default value void someMethod() { Complex localComplex; // not set to the default value IO.println(complexField); // prints Complex(0, 0) IO.println(localComplex); // does not compile! } } 99 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 Variable 'localComplex' might not have been initialized -
Arrays Arrays are stored in a flattened representation var complexes
= new Complex[10]; // each element is initialized with Complex.default The array is fully flattened 100 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Backward Compatibility Issues Primitive class instances on stack can be
null var complexMap = new HashMap<String, Complex>(); Complex complex = complexMap.get("origin"); // complex is null 101 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Null Primitive Instances are Allowed on Stack Primitive class instances
on stack can be null value class Holder { Complex c; // null restricted Holder(Complex c) { Objects.requireNonNull(c, "c is null"); // good practice this.c = c; } Complex f(Complex c) { // c is nullable here return c == null ? Complex.default : c; } } 102 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
From the VM Point of View We need a handshake
between the field and the class - the field has to be marked as null_restricted - the VM has to check that the type is a primitive class The latter can be done using a stricter LoadableDescriptors (fails if not a primitive class) So no backward compatible change from an existing class to a primitive class and vice-versa 103 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
From Identity to Primitive Identity Class Give up Identity Value
Class Get scalarization and 56 bits flattening Give up Encapsulation Primitive Class 104 Copyright © 2026, Oracle and/or its affiliates | Get full flattening, default values and operator overloading 10/4/2026 -
Back to Planet Earth 105 Copyright © 2026, Oracle and/or
its affiliates 10/4/2026 -
So, Will Valhalla Fix Tony’s 1B$ mistake? Short answer: no
106 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Roadmap to Valhalla in JDK 28 JEP 513: Flexible Constructor
Bodies (Final in 25) JEP 401: Value Objects (Preview) JEP 539: Strict Field Initialization in the JVM (Preview) 107 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Roadmap to Valhalla for Later JEP Draft: Primitive Class +
non-null fields? JEP 402: Enhanced Primitive Boxing (int ≈ Integer!) Type Classes (operator overloading for primitive class) Parametric JVM (List) 108 Copyright © 2026, Oracle and/or its affiliates | 10/4/2026 -
Valhalla Features Value Objects Null restricted syntax Primitive class Parametric
JVM 109 Copyright © 2026, Oracle and/or its affiliates | Preview in 28 Failed experiment Future proposal Future direction 10/4/2026