JEP 529 ships in JDK 26 with no substantial changes since JDK 25. After five years and eleven rounds, the story behind the wait is actually a masterclass in JDK planning constraints — and in what happens when a good API design depends on language features that don’t exist yet.
1. Eleven Times and Counting
No API in the JDK’s modern history has spent as long in incubation as the Vector API. Ten versions. Eleven JEPs. Five calendar years. And counting — explicitly, deliberately, because the language it needs does not exist yet.
JEP 529, re-incubating the Vector API in JDK 26, was targeted by Mark Reinhold in October 2025, delivered in March 2026, and carries a note that has appeared in every incubation since JDK 16: “The Vector API will incubate until necessary features of Project Valhalla become available as preview features.” As InfoQ confirmed on JDK 26’s release day: no substantial implementation changes since JDK 25. Not because the Vector API team is slow, not because the SIMD hardware is unsupported, but because the API is deliberately waiting to be designed right.
This is a fascinating situation on multiple levels. The Vector API works today — you can use it right now on JDK 16 through 26 to write SIMD-accelerated Java code that genuinely outperforms scalar implementations on supported hardware. It is not broken. It is not experimental in its implementation. It is being held at the incubation stage because graduating it to preview would commit the JDK to an API shape that Valhalla will require it to abandon. And that trade-off — accept a worse API shape now vs wait for a better one — is the core tension the JDK team has been navigating for five years.
Understanding why leads directly into the deepest currents of ongoing JDK design: how value types, generics over primitives, and the identity model interact, and why all three need to arrive together for the Vector API to make sense at the language level.
2. What the Vector API Actually Does
Before examining the blocker, it is worth being precise about what the Vector API provides, because the level of capability it offers is genuinely impressive even in its current incubating form.
SIMD — Single Instruction, Multiple Data — is the hardware mechanism by which modern CPUs can apply a single operation to multiple data elements simultaneously. An AVX-512-equipped x86 processor can, in a single instruction, add sixteen 32-bit integers, multiply eight 64-bit floats, or XOR four 128-bit values. The performance difference between vectorised and scalar code on numerical workloads can be 4×, 8×, or 16× — the multiplicative factor being the vector width divided by the element size.
Java’s auto-vectoriser — the HotSpot JIT’s attempt to automatically recognise loops that could be vectorised — exists but is limited in what it can reliably detect. The Vector API gives developers explicit control: you write the vectorised operations directly, using an API that the JIT compiler recognises and lowers to the appropriate SIMD instructions on x64 (using AVX, AVX2, AVX-512) and AArch64 (using NEON and SVE). As the JEP states: vector computations that reliably compile at runtime to optimal vector instructions on supported CPU architectures, achieving performance superior to equivalent scalar computations.
Java — Vector API today (incubating, JDK 16–26)
// Requires --add-modules jdk.incubator.vector
import jdk.incubator.vector.*;
public class VectorSumExample {
private static final VectorSpecies<Float> SPECIES =
FloatVector.SPECIES_PREFERRED; // picks widest supported SIMD width
public static float vectorisedDotProduct(float[] a, float[] b) {
var acc = FloatVector.zero(SPECIES);
int i = 0;
// Main vectorised loop — processes SPECIES.length() floats per iteration
for (; i < SPECIES.loopBound(a.length); i += SPECIES.length()) {
var va = FloatVector.fromArray(SPECIES, a, i);
var vb = FloatVector.fromArray(SPECIES, b, i);
acc = va.fma(vb, acc); // fused multiply-add — one instruction
}
float result = acc.reduceLanes(VectorOperators.ADD);
// Scalar tail — handles remainder elements not fitting a full vector
for (; i < a.length; i++) {
result += a[i] * b[i];
}
return result;
}
}
This code works. It compiles. On a machine with AVX-512, SPECIES_PREFERRED resolves to 16 lanes of 32-bit float — sixteen multiply-add operations per iteration, in a single CPU instruction. The JIT recognises the API calls and emits the correct SIMD instructions. For numerical computing, signal processing, machine learning feature engineering, or cryptographic operations, this is genuinely transformative performance in pure Java.
The only catch is that --add-modules jdk.incubator.vector on every compiler and JVM invocation. And the implicit warning: this API is not stable. Its type signatures may change.
3. The Complete Incubation History
Ten rounds of incubation were delivered in JDK 16 through JDK 25, each carrying the Vector API forward. Not all rounds were equal — some brought substantial additions, others simply held the API stable while waiting for downstream dependencies to catch up. The full timeline reveals the pattern clearly.
Vector API incubation timeline — JDK 16 to JDK 26
| JDK | JEP | Release | Significant changes | Status |
|---|---|---|---|---|
| JDK 16 | JEP 338 | Mar 2021 | First incubation — initial API surface, x64 only | 1st incubation |
| JDK 17 | JEP 414 | Sep 2021 | AArch64 support added; cross-lane operations expanded | Changes |
| JDK 18 | JEP 417 | Mar 2022 | Further AArch64 operations; transcendental operations via SVML/SLEEF | Changes |
| JDK 19 | JEP 426 | Sep 2022 | Alignment with structured access to memory (MemorySegment); performance improvements | Changes |
| JDK 20 | JEP 438 | Mar 2023 | Minor API refinements; continued memory segment alignment | Minor changes |
| JDK 21 | JEP 448 | Sep 2023 | Alignment updates; operations now work with MemorySegment GA API (FFM) | Minor changes |
| JDK 22 | JEP 460 | Mar 2024 | No API changes — first explicit hold for Valhalla | Hold |
| JDK 23 | JEP 469 | Sep 2024 | No API changes — holding for Valhalla | Hold |
| JDK 24 | JEP 489 | Mar 2025 | No API changes — holding for Valhalla | Hold |
| JDK 25 | JEP 510 | Sep 2025 | No API changes — holding for Valhalla | Hold |
| JDK 26 | JEP 529 | Mar 2026 | No API changes — holding for Valhalla preview features | 11th · Active hold |
4. The Actual Blocker: Why Valhalla Generics Matter
The JEP is admirably direct about what is blocking graduation. From the JEP itself: “The Vector API uses box types (e.g., Integer) as proxies for primitive types (e.g., int). This decision is forced by the current limitations of Java generics, which are hostile to primitive types. When Project Valhalla eventually introduces more capable generics then the current decision will seem awkward, and will likely need changing.”
This sentence contains the entire explanation, but it needs unpacking. Java generics, as they exist today, are erased at compile time and constrained at the type level to work only with reference types. You cannot write Vector<int> in Java today — the generic type parameter must be a reference type. So the Vector API uses the boxed equivalent: Vector<Integer> for a vector of 32-bit integers, Vector<Float> for a vector of 32-bit floats, Vector<Long> for 64-bit integers, and so on.
From an ergonomic standpoint, this is already slightly awkward — the types name boxed objects when what you are actually working with are primitive values packed into SIMD registers. But the deeper problem is what happens once Valhalla’s generic specialisation arrives. At that point, Vector<int> becomes a meaningful type — not a boxed type, but a genuine parameterisation over a primitive. The current API’s use of Vector<Integer> would then look not just awkward but wrong. Worse, it might need to coexist with a new Vector<int> form in a confusing way, or it would need to be changed in a way that breaks backwards compatibility for all existing Vector API code.
The precise Valhalla dependency: JEP 529 states the expected future explicitly: “We expect, further, to leverage Project Valhalla’s generic specialization of value classes so that instances of
Vector<E>are value objects, where E is a primitive class such asintinstead of its boxed classInteger. Subtypes ofVector<E>for specific types, such asIntVector, might not be required once we have generic specialization over primitive classes.” In other words:IntVector,FloatVector,LongVector— the current concrete subtypes — exist only because generic primitives don’t. Once they do, the entire type hierarchy of the Vector API simplifies.
5. The Boxing Problem in Concrete Terms
To understand why this matters in practice, consider what the boxing requirement costs. When you write VectorSpecies<Float>, the type parameter Float is a reference type — an object on the heap, with an object header and identity. At the SIMD register level, however, a 512-bit AVX-512 register holding sixteen single-precision floats contains no object headers. It contains sixteen packed 32-bit values, directly. The boxing is a pure type-system fiction that the JIT compiler has to see through entirely.
In practice, the JIT is good enough at this that you pay no boxing cost at runtime for the SIMD operations themselves. The compiler recognises the Vector API intrinsics and emits the appropriate SIMD instructions, discarding any object-oriented indirection. But the fiction creates real costs at the API design level: every method signature that could be cleaner with primitive type parameters is instead written with boxed ones. The distinction between IntVector and FloatVector — which in a world with generic primitives could simply be Vector<int> and Vector<float> — is currently encoded through explicit subclasses, multiplying the API surface.
Java — current API shape vs future Valhalla shape (illustrative)
// CURRENT: boxed type parameter, explicit subtypes per primitive VectorSpecies<Float> floatSpecies = FloatVector.SPECIES_256; VectorSpecies<Integer> intSpecies = IntVector.SPECIES_256; VectorSpecies<Long> longSpecies = LongVector.SPECIES_256; FloatVector fv = FloatVector.fromArray(floatSpecies, floatData, 0); IntVector iv = IntVector.fromArray(intSpecies, intData, 0); // FUTURE (after Valhalla generic specialisation — not available yet): // E is a primitive class — no boxing, no IntVector/FloatVector subclasses needed VectorSpecies<float> floatSpecies = Vector.species(float.class, 256); Vector<float> fv = Vector.fromArray(floatSpecies, floatData, 0); // Same generic type, no distinct subclasses, no boxed proxy
6. Value Classes: The Other Half of the Dependency
Generic specialisation over primitives is not the only Valhalla dependency. The JEP is equally explicit about value classes. From JEP 529: “We expect ultimately to declare vector classes as value classes. For ongoing efforts to align the Vector API with Valhalla, see the lworld+vector branch of Project Valhalla’s development repository.”
A value class, in Valhalla’s model, is a class whose instances lack object identity. Two instances of a value class are equal if and only if their fields are equal — there is no concept of “the same object” that is distinct from “an object with the same value.” This is semantically correct for vectors: a vector of sixteen floats containing [1.0, 2.0, ..., 16.0] is simply that vector — its identity as a heap object is irrelevant. Carrying object identity overhead for vectors is both wasteful and conceptually wrong.
Currently, Vector classes are declared as value-based classes — a weaker advisory designation that says “treat these as if they had value semantics, but we cannot enforce it yet.” JEP 401 (Value Classes and Objects), which is targeted for preview in JDK 26 or shortly after, is the JEP that will make value classes a formal language feature. Once it ships as a preview, the Vector API team can begin adapting the Vector classes to be proper value classes — and at that point, the API can leave incubation and enter preview itself.
JEP 401 is the direct predecessor: JEP 401 (Value Classes and Objects) has early-access builds implementing value classes with preview features in early-access builds of JDK 26. The anticipated delivery is now within the next 1–2 releases. When it ships as a preview, the Vector API can be adapted to declare
Vector<E>and its subtypes as value classes — and graduation from incubation to preview becomes possible. JEP 500 (Prepare to Make Final Mean Final), also in JDK 26, is a preparatory step for the object model changes Valhalla requires.
7. What JEP 529 Actually Changed (Or Didn’t)
The JEP 529 text is explicit and brief on this point: “We here propose to re-incubate the Vector API in JDK 26 with no API changes and no substantial implementation changes relative to JDK 25.” This is an intentional and reasoned decision, not a failure to ship.
The reason no changes were made is the same reason the API is still incubating: making changes now would be changes to a shape that is about to change again when Valhalla lands. Every method signature refined today is a signature that might need to change again — and with it, every piece of user code that adopted the incubating API. The JDK team’s calculation is correct: stability during the hold period is more valuable than incremental refinement of an API that is known to be structurally wrong at the type-parameter level.
However, “no substantial implementation changes” does not mean the implementation stood still entirely. The JIT compiler’s handling of Vector API intrinsics continues to improve across JDK releases independently of the API surface. The code you write in JDK 26 performs better than the same code in JDK 16 not because the API changed, but because the HotSpot compiler improved its lowering of Vector API operations to SIMD instructions. Float16 support is under active development on the vectorIntrinsics+fp16 branch of Project Panama. RISC-V support, contributed by the community, has been progressing.
8. JEP 500: The Quiet Signal That Valhalla Is Closer
The most revealing signal in JDK 26 for Vector API watchers is not JEP 529 itself — it is JEP 500: Prepare to Make Final Mean Final. This JEP changes the semantics of the final keyword in ways that are preparatory for Valhalla’s object model.
Currently, the final keyword on a field provides a write-once guarantee that the compiler can use for optimisation, but does not prevent identity-sensitive operations. Valhalla’s value classes require a stricter interpretation: a field that is final in a value object is final in an absolute sense — there is no identity through which it could be mutated via reflection tricks or unsafe operations. JEP 500 begins this tightening: it introduces warnings and eventual errors for code that attempts to mutate final fields via reflection, setting up the platform for value classes to make their stricter guarantees credible.
As Hanno Embregts observed in his Java 26 analysis: “My hope is that the first JEPs out of Project Valhalla will be announced later this year. That hope is fuelled by some of Java 26’s changes as they feel like appropriate preparation steps for the first Valhalla features — this is especially true for JEPs 500 and 529.” The combination of JEP 500 (fixing the preconditions for value classes) and JEP 529 (holding the Vector API ready to adopt them) is the JDK doing its preparation work in public.
9. Why the Incubation Model Exists and What It Gets Right
The Vector API’s eleven-incubation journey is an extreme case of a process that the JDK uses deliberately. As the JavaCodeGeeks analysis of Java’s future trajectory notes: the six-month model allows features to mature through multiple preview rounds across releases without blocking other improvements. This patience-enabling structure proves crucial for complex initiatives like Valhalla, which require extensive real-world testing before stabilisation.
The incubation stage — formally defined in JEP 11 — exists specifically for APIs that need real-world feedback before the JDK commits to them permanently. An incubating API lives in the jdk.incubator.* module namespace, requires an explicit --add-modules flag to use, is not part of the Java SE standard (so it cannot be relied upon by libraries with wide reach), and carries an explicit promise that it may change in future versions. Crucially, it can ship in a release even when the team knows the API is structurally imperfect — because getting real-world usage data from the imperfect version is more valuable than shipping nothing while waiting for perfection.
What the incubation constraint protects you from: The
jdk.incubator.vectormodule requirement is not bureaucratic friction. It is a deliberate signal: this API is in thejdk.incubatornamespace, meaning no library on Maven Central should depend on it transitively. If Spring, Guava, or Jackson depended on an incubating API, millions of applications would break each time that API changed. The module requirement keeps incubating APIs out of the library ecosystem’s transitive dependency graph until the API is stable enough to commit to permanently.
10. Using the Vector API Today: Is It Worth It?
Given eleven incubations and an explicitly unstable API contract, the practical question for a working Java engineer is: should you use the Vector API in production code today?
The answer is a conditional yes — and the condition is domain-specific. For performance-critical numerical, cryptographic, or data-processing code where the team is prepared to handle API changes at major JDK boundaries, the Vector API is the right tool. The performance gains are real: a hand-vectorised dot product using the Vector API with AVX-512 hardware is legitimately 10–16× faster than the scalar equivalent. No amount of scalar optimisation closes that gap. Furthermore, the JIT does actually recognise and compile the API to SIMD instructions reliably in JDK 21+.
For general application code — web services, database access layers, business logic — the Vector API is not relevant. Auto-vectorisation handles the numerical portions of typical application code adequately, and the module flag overhead and API instability cost are not justified by any realistic performance gain.
| Use case | Vector API today? | Rationale |
|---|---|---|
| ML inference / embedding computation | Yes | Dot products, activations, matrix operations — exactly the workloads SIMD dominates. Real-world 4–16× gains documented. |
| Cryptographic primitives (AES, SHA) | Yes | Bitwise and arithmetic operations on fixed-width data — ideal Vector API workload. JDK’s own crypto uses intrinsics derived from this approach. |
| Signal/image processing (FFT, convolution) | Yes | Complex number arithmetic, bulk float operations — a primary design target of the API. |
| SIMD-accelerated text search / parsing | Conditional | Viable, but the API is not optimised for byte-level operations the way SWAR techniques are. Measure carefully. |
| General web / business logic | No | Not applicable. Module flag overhead, API instability, and no meaningful performance benefit for this workload class. |
| Library code (open-source, Maven) | No | An incubating API must not appear in transitive dependencies. Wait for graduation before including in any library with external users. |
11. When Does It Graduate?
The graduation condition is precisely stated in every Vector API JEP: “The Vector API will incubate until necessary features of Project Valhalla become available as preview features. At that time, we will adapt the Vector API and its implementation to use them and then promote the Vector API from incubation to preview.”
So the question reduces to: when does Valhalla ship its relevant preview features? The most optimistic reading of the current signals — JEP 401 in early-access builds, JEP 500 in JDK 26, active work on the lworld+vector branch — points to JDK 27 (September 2026) or JDK 28 (March 2027) as the likely window for Valhalla value classes to enter preview. JEP 401 has been described by InfoQ as targeted for “JDK 27 at this time,” while acknowledging that draft JEPs can change. Even after JEP 401 previews, the Vector API team will need an adaptation period — likely one additional JDK cycle — to retrofit the API to use value classes and primitive generics before it can enter its own preview.
Realistically: the Vector API is unlikely to be in preview before JDK 28 (March 2027) and may not be GA before JDK 30 or 31 (2027–2028). That is twelve to fourteen incubations in total. It will also be, when it arrives, one of the most carefully designed and correctly shaped APIs the JDK has ever shipped — because it will have been held until the language could support it properly.
The right way to read this story: The eleven incubations are not a failure of the Java release process — they are evidence that it is working as designed. The alternative would have been to graduate the Vector API with
Vector<Integer>and explicitIntVector/FloatVectorsubtypes, permanently committing the JDK to an API shape that everyone involved knows is a workaround for missing language features. The incubation model gives the team the ability to say, publicly and honestly: this API exists, you can use it, and we reserve the right to make it correct when the language catches up.
12. What We Have Learned
The Vector API’s eleven-incubation journey is the most instructive case study in the modern JDK’s development model. Here is the distilled picture:
- JEP 529 re-incubates the Vector API in JDK 26 with no API changes and no substantial implementation changes since JDK 25. This is deliberate, not a shipping failure.
- The Vector API works today for SIMD-accelerated numerical, cryptographic, and signal-processing code on x64 (AVX/AVX-512) and AArch64 (NEON/SVE). The performance gains — 4–16× vs scalar — are real. The instability cost is an API signature change risk at major JDK boundaries.
- The blocking dependency is dual: Project Valhalla’s generic specialisation over primitive types (so
Vector<int>becomes legal), and value classes (soVectorinstances can be declared as lacking object identity). Both are prerequisites for the API to have the correct shape permanently. - Current awkwardness: boxed type parameters (
Vector<Float>instead ofVector<float>) and explicit subclasses (IntVector,FloatVector) exist solely because Java generics cannot express primitive type parameters today. Once Valhalla lands, these will be unnecessary. - JEP 401 (Value Classes and Objects) is the direct predecessor. Early-access builds exist. JEP 500 in JDK 26 (Prepare to Make Final Mean Final) is a preparatory tightening of the object model ahead of value class support.
- Graduation timeline: realistically JDK 28–30 (2027–2028), contingent on Valhalla value classes entering preview in JDK 27. Twelve to fourteen total incubations is a plausible final count.
- The incubation model is working exactly as designed. Graduating a structurally wrong API permanently — to avoid an eleventh incubation — would have been the mistake. The wait is the right call.
Thank you!
We will contact you soon.
Eleftheria DrosopoulouMarch 27th, 2026Last Updated: March 20th, 2026

This site uses Akismet to reduce spam. Learn how your comment data is processed.