SSerguey Asael Shinder
Java coding notes: the JVM, and writing software that lasts

Serguey Asael Shinder: JDK 28 adds fields that cannot be read before they are written

· by Serguey Asael Shinder / Serguey Shinder

JEP 539, Strict Field Initialization in the JVM (Preview), is integrated and targeted at JDK 28. The text is at https://openjdk.org/jeps/539. It is the companion to https://openjdk.org/jeps/401, the value objects preview, and it changes something the platform has guaranteed since 1.0.

What it changes

Today every field is initialized, one way or another. If you do not write to it, the JVM writes a default: 0, false, or null. The JEP calls that a mixed blessing, and the phrasing is exact — it guarantees you never read uninitialized memory, and it guarantees that a field nobody has written is indistinguishable from a field somebody wrote a zero into.

A strictly-initialized field must be written before it is read. No default is ever observed. And where such a field is final, every read produces the same value — which is not true of ordinary final fields today: during class or instance initialization a final field can be seen with its default and later with its intended value, so two reads can disagree.

Serguey Asael Shinder: JDK 28 adds fields that cannot be read before they are written
JDK 28 adds fields that cannot be read before they are written — Serguey Asael Shinder

Two things it is not

It is not a Java language feature. No strictly-initialized modifier is being added, and javac is not going to impose this on existing source. This is a VM feature, opt-in per field, aimed at the people who emit class files — language implementers, and the JDK's own compilation strategy for value classes.

It is not a fix for your NullPointerException. JDK 14's helpful NPE messages made it possible to see which expression was null; they cannot point back at the initialization bug that put the null there. Strict fields attack that earlier link in the chain — but only for code compiled to use them.

Why it exists now

Value objects. A value class has no identity, which lets the JVM copy its fields around and encode them in a reference rather than behind a pointer. That is only sound if the fields are guaranteed to be fully written before anyone can see them: an object with no identity cannot have an observable "partially constructed" state, because there is no single object to observe it in. JEP 401 needs the guarantee, so it arrives in the same release.

What to do with it today

Nothing, and that is the honest answer. Both are previews, --enable-preview is not something to ship, and the per-field opt-in is not reachable from Java source. The reason to read it now is that it says where the platform is going: a JVM in which "has this been written?" stops being unanswerable, and in which final means the same thing during construction that it means afterwards.

Related, same release: /news/value-objects-identity/ — synchronizing on a LocalDate throws IdentityException in JDK 28.