JDK 26 and JavaOne: When the Conference overshadows the Release - JVM Weekly vol. 167
While everyone has new JDK 26, this is the edition where I deeply envy everybody who's at JavaOne right now 😁
Let’s be honest - if JDK 26 had dropped on a quiet Tuesday without JavaOne in the background, we’d mostly be talking about HTTP/3 and the fact that Applets are finally gone (RIP, nobody’s crying). It’s a solid but not exactly revolutionary release — ten JEPs, half of which are yet another round of previews. But JavaOne 2026 is a completely different story. Java Verified Portfolio, Project Detroit back from the dead, Helidon moving to OpenJDK, Koog for Java from JetBrains... suddenly it turns out this isn’t the week of JDK 26 - it’s the week the Java ecosystem officially went all-in on AI and agents. And that’s genuinely interesting.
So today we’re doing a two-for-one - first we’ll walk through JDK 26 JEP by JEP and things other than just JEP’s (because there’s still plenty to discuss), and then we’ll get to what actually set the internet on fire this week. Let’s go.
1. JDK 26 Released!
Unlike JDK 25, which came with a massive 24 JEPs (including a significant LTS release milestone), JDK 26 is a much smaller release with only 10 JEPs. However, don’t let the smaller number fool you - this release brings some genuinely interesting changes, including the long-awaited HTTP/3 support and significant GC improvements.
Now, let’s go through the complete list of changes in the new edition.
Exegi monumentum - Stable Feature
JEP 517: HTTP/3 for the HTTP Client API
JEP 517 finally brings HTTP/3 support to the Java Platform (at least natively). The HTTP Client API (introduced in JDK 11) is updated to support the HTTP/3 protocol, which uses QUIC transport instead of TCP.
Why HTTP/3 matters: HTTP/3 offers potentially faster handshakes, avoidance of head-of-line blocking, and more reliable transport especially in environments with high packet loss. It’s already supported by most browsers and deployed on about a third of all websites.
Usage: HTTP/3 is opt-in. You can enable it per-client or per-request:
var client = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_3)
.build();Or you can enable HTTP/3 for a specific request:
var request = HttpRequest.newBuilder(URI.create("https://example.com/"))
.version(HttpClient.Version.HTTP_3)
.GET().build();The implementation transparently downgrades to HTTP/2 or HTTP/1.1 if the target server doesn’t support HTTP/3. Various discovery modes are available to control this behavior via the H3_DISCOVERY request option.
Goodbye, Old Friends - Removals and Preparations
JEP 504: Remove the Applet API
Probably the second biggest announcement this week. JEP 504 finally removes the Applet API from the Java Platform. This has been a long time coming – the API was deprecated in JDK 9 (2017), deprecated for removal in JDK 17 (2021), and now, with the Security Manager permanently disabled in JDK 24, there’s simply no reason to keep this obsolete code around.
What gets removed: The entire java.applet package (Applet, AppletContext, AppletStub, AudioClip), java.beans.AppletInitializer, javax.swing.JApplet, and any API elements that reference these classes.
Web browsers haven’t supported applets for years, and there hasn’t been a way to run applets using the JDK since the appletviewer tool was removed in JDK 11. It’s time to say goodbye to this relic of Java’s early web days.
Does anybody miss the old guy?
JEP 500: Prepare to Make Final Mean Final
JEP 500 begins the process of enforcing the integrity of final fields. Currently, the deep reflection API (setAccessible and set methods of java.lang.reflect.Field) allows final fields to be mutated at will – making the final keyword essentially meaningless from a runtime perspective.
The problem: Final fields represent immutable state, crucial for reasoning about correctness and enabling JVM optimizations like constant folding. But the ability to mutate them via reflection undermines all of this.
The solution: In JDK 26, mutating final fields via deep reflection will issue warnings by default. A future release will throw exceptions instead. Developers can opt in to final field mutation using --enable-final-field-mutation=MODULE_NAME when necessary.
Serialization libraries should migrate to using sun.reflect.ReflectionFactory, which provides a supported way to deserialize objects with final fields without requiring the --enable-final-field-mutation flag.
Performance - VM Internals
JEP 516: Ahead-of-Time Object Caching with Any GC
JEP 516 enhances the AOT cache (introduced in JEP 483) so that it can be used with any garbage collector, including ZGC. This is a significant improvement for Project Leyden’s startup optimization efforts.
The problem: Previously, cached Java objects were stored in a GC-specific format, making the AOT cache incompatible with ZGC. This forced users to choose between low-latency garbage collection OR fast startup - but not both.
The solution: Objects can now be cached in a GC-agnostic format using logical indices instead of memory addresses. When the cache is loaded, a background thread materializes objects one by one, converting indices to actual addresses appropriate for the current GC.
The JDK now includes two baseline AOT caches – one GC-agnostic and one GC-specific – and automatically selects the appropriate one based on the environment.
JEP 522: G1 GC: Improve Throughput by Reducing Synchronization
This time, a bit more theory needed.
G1 needs to know which parts of the Java heap were modified by the application so it can perform garbage collection safely. To do this, the heap is divided into small chunks called cards, and G1 maintains a card table—a simple structure that records which cards have been changed. Every time your code updates an object reference, the corresponding card is marked.
Before JEP 522, both application threads and garbage-collection threads updated the same card table. Because many threads were touching this shared structure, G1 had to use synchronization. Under heavy load, this locking became a bottleneck and reduced overall throughput.
JEP 522 changes this by introducing a second card table. Application threads now update one card table without any locking, using much simpler and faster write-barrier code. At the same time, GC threads work on the other card table. When G1 needs to hand work from the application to the GC, it simply swaps the two tables atomically.
This matters because updating object references is one of the most frequent operations in Java programs. Making this path cheaper improves performance across the board, especially for highly concurrent applications.
In practice, this results in a 5–15% throughput improvement for applications that heavily modify object references, and up to 5% improvement even for others. The write-barrier code was reduced from around 50 CPU instructions to about 12 on x64 systems. The extra memory cost is small - about 2 MB per 1 GB of heap - and is largely offset by memory optimizations introduced in recent JDK releases.
Nihil Novi Sub Sole - Preview Features Continue
JEP 526: Lazy Constants (Second Preview)
The goal of LazyConstant is to compute a value exactly once, in a thread-safe way, but only when it’s first accessed, not at class-initialization time. At the same time, it is designed so that once the value is initialized, the JVM can treat it like a constant and apply constant-folding and inlining optimizations, avoiding repeated reads or synchronization overhead.
In short: LazyConstant combines lazy initialization, safe concurrency, and JIT-level performance close to real constants. JEP 526 re-previews the API for deferred immutability, now renamed from StableValue to LazyConstant. The API has been significantly simplified to focus on high-level use cases.
Key changes from JDK 25:
Renamed from StableValue to LazyConstant
Removed low-level methods (orElseSet, setOrThrow, trySet)
Factory methods for lazy lists and maps moved to List.ofLazy() and Map.ofLazy()
null is no longer allowed as a computed value
private final LazyConstant<Logger> logger
= LazyConstant.of(() -> Logger.create(OrderController.class));
void submitOrder() {
logger.get().info("order started"); // Initialized on first access
}JEP 525: Structured Concurrency (Sixth Preview)
Structured Concurrency API treats groups of related tasks running in different threads as single units of work, streamlining error handling and cancellation. JEP 525 continues the preview of the Structured Concurrency API with minor refinements.
Changes in this new preview:
New Joiner.onTimeout() method for handling timeout expiration
allSuccessfulOrThrow() now returns List<T> instead of Stream<Subtask<T>>
anySuccessfulResultOrThrow() renamed to anySuccessfulOrThrow()
Static open method now takes UnaryOperator instead of Function
Response handle() throws InterruptedException {
try (var scope = StructuredTaskScope.open()) {
Subtask<String> user = scope.fork(() -> findUser());
Subtask<Integer> order = scope.fork(() -> fetchOrder());
scope.join();
return new Response(user.get(), order.get());
}
}JEP 524: PEM Encodings of Cryptographic Objects (Second Preview)
PEM encoding/decoding API provides a concise way to convert between PEM text and cryptographic objects like keys, certificates, and certificate revocation list. JEP 524 continues the preview of it with several refinements.
Changes:
PEMRecord is now named PEM and includes a decode() method
EncryptedPrivateKeyInfo gets new encrypt() and getKeyPair() methods
PEMEncoder and PEMDecoder now support KeyPair and PKCS8EncodedKeySpec encryption/decryption
String pem = PEMEncoder.of().encodeToString(privateKey);PrivateKey key = PEMDecoder.of().decode(pem, PrivateKey.class);JEP 530: Primitive Types in Patterns, instanceof, and switch (Fourth Preview)
The feature enables uniform (finally!) data usage with type patterns for all types, whether primitive or reference, and allows switch to process values of any primitive type including boolean, float, double, and long. JEP 530 previews for the fourth time the extension of pattern matching to primitive types... so you probably know the drill 😉
Changes in this preview: Enhanced definition of unconditional exactness and tighter dominance checks in switch constructs. These changes enable the compiler to identify a wider range of coding errors, although some previously legal switch constructs will now be rejected.
// Primitive type patterns in switch
switch (x.getYearlyFlights()) {
case 0 -> "No flights";
case 1 -> "One flight";
case int i when i >= 100 -> "Gold status!";
case int i -> "Regular: " + i + " flights";
}
// instanceof with primitives - safe conversion check
int i = 1000;
if (i instanceof byte b) {
// Only enters if i fits in a byte
}JEP 529: Vector API (Eleventh Incubator)
The API legend (or rather myth) allowing to express vector computations that compile to optimal SIMD instructions on supported CPUs. JEP 529 continues the incubation of the Vector API without substantial changes. As a reminder - the Vector API will remain in incubation until necessary features from Project Valhalla (value classes) become available as preview features. At that point, it will be adapted to use them and promoted to preview status.
And with that, a small comment at the end... I honestly expected to see more Valhalla here by JDK 26, but we still don’t have it.
So it looks like we’ll probably have to wait a bit longer for the Vector API as well.
2. Beyond the JEPs - Notable Changes from Release Notes
While 10 JEPs make the headlines, JDK 26’s release notes contain a handful of smaller changes that are worth highlighting - some practical, some symbolic, and one that the internet will absolutely love.
Javadoc Dark Mode
Yes, you read that right. The API documentation generated by Javadoc now ships with a dark theme. You can toggle between light, dark, and system-default using the new theme button in the navigation bar. Is it a game-changer? No. Will it make your 2 AM debugging sessions marginally less painful? Absolutely.
Thread.stop() Is Finally Gone
In a poetic parallel to the Applet API removal (JEP 504), Java 26 also removes Thread.stop() - over 27 years after it was first marked as deprecated. That’s not a typo. The method was deprecated back in JDK 1.2, which shipped in December 1998. For context, Google was founded that same year.
There’s no JEP for this one - it’s tracked in the bug tracker under JDK-8368226. Together with the Applet API, JDK 26 is having a real “spring cleaning” moment.
JDBC 4.5
JDK 26 includes support for the JDBC 4.5 Maintenance Release. The headline change: Array, Blob, Clob, NClob, and SQLXML interfaces now extend AutoCloseable, with a default close() implementation that delegates to free(). This means you can finally use them in try-with-resources blocks without wrapping.
The release also adds default implementations of the quoted identifier methods (previously on Statement since JDK 9) to the Connection interface. A heads-up: if your JDBC driver has private or protected implementations of these newly-added default methods, you may hit compatibility issues. But I hope you do not have your own JDBC driver... unless you are in very interesting place 😁
UUID v7 Support
A new factory method java.util.UUID.ofEpochMillis(long) has been added, allowing creation of Type 7 UUIDs from a Unix epoch timestamp. Type 7 UUIDs are time-ordered and database-friendly - if you’ve been reaching for external libraries for this, you can stop now.
GC CPU Time Tracking
A new getTotalGcCpuTime() method on java.lang.management.MemoryMXBean returns the accumulated CPU time in nanoseconds for GC-related activity. Combined with the new -Xlog:cpu output that now prints a full breakdown table of VM CPU usage at exit, this gives you much better observability into where your JVM’s CPU cycles are actually going.
HPKE and Post-Quantum Ready JAR Signing
Two non-JEP security additions that Oracle is highlighting prominently: Java 26 ships with Hybrid Public Key Encryption (HPKE) out of the box, and introduces post-quantum ready JAR signing. The HPKE support is interesting on its own, but it’s the JAR signing part that has longer-term implications for supply chain security — especially with JEP 527 (Post-Quantum Hybrid Key Exchange for TLS 1.3) already targeted for JDK 27. Oracle is clearly building out the post-quantum story piece by piece.
Virtual Threads: Unmounting During Class Initialization
A small but significant Loom improvement: virtual threads now unmount from the carrier thread when waiting for another thread to execute a class initializer. Previously, this was one of the remaining scenarios where a virtual thread would pin its carrier — making the platform thread unavailable for other work. If you’ve been tracking the gradual elimination of pinning scenarios since JDK 21, this is another step in the right direction.
3. JavaOne 2026 Announcements
JDK 26’s release day coincides with JavaOne 2026 (March 17–19, Redwood Shores, CA), and Oracle used the occasion to make several ecosystem announcements that arguably overshadow the JDK release itself.
Here, you will find the Keynote and... it was a loaded one - and the title says everything.
Here you will find the most important non-directly-JDK related announcements.
Java Verified Portfolio (JVP)
The biggest announcement is the introduction of the Java Verified Portfolio - a curated, Oracle-supported collection of tools, frameworks, libraries, and services that extends enterprise support beyond the JDK itself.
At launch, JVP includes:
Helidon - Oracle’s open-source, cloud-native microservices framework built on Virtual Threads, with LangChain4j integration and MCP-based AI agent support
JavaFX - reintroduced under commercial support after a multi-year gap, driven by demand for rich interactive UIs in AI analytics and data visualization
Java Platform Extension for VS Code
JVP is included at no additional cost for Java SE subscribers and OCI customers. Oracle is clearly positioning this as a supply-chain risk reduction play — instead of tracking multiple upstream sources with varying support timelines, you get a single, Oracle-governed source of truth with roadmap alignment to JDK releases.
Project Detroit - Java and JavaScript/Python Interop
While JVP was the most important, this one is the most forward-looking announcement: Oracle introduced Project Detroit, designed to enable fast, seamless interoperability between Java, JavaScript, and Python.
If the name sounds familiar, that’s because it’s a resurrection. The original Detroit project was created in February 2018 as a bridge between Java and JavaScript via V8, but it never got off the ground and was dissolved in September 2024. In February 2026, Sundararajan Athijegannathan (who offered to lead the project) proposed its recreation, noting that “with the rise of AI, there is also interest in accessing AI functionality written in Python from Java applications.”
The approach is fundamentally different from what we had with Nashorn or GraalVM’s Truffle-based language implementations. As Bernard Traversat (VP Software Development at Oracle) explained at the JavaOne briefing: instead of reimplementing JavaScript or Python on top of the JVM - where you’re constantly “swimming against the current” chasing language spec corner cases - Detroit embeds the V8 and CPython runtimes directly inside the JVM process via the FFM API. This gives you native compatibility for free and clear heap isolation between Java and the guest language.
The irony here is hard to miss. Oracle JDK 24 was the last release to include the experimental Graal JIT compiler, and GraalVM for JDK 24 was the last version licensed under Java SE - effectively detaching GraalVM’s polyglot story from the JDK ecosystem train. And now, barely a year and a half later, Oracle is rebuilding the polyglot interop capability from scratch, this time with a radically simpler architecture - to be fair, Detroit’s approach is architecturally quite different from Truffle.
The project team includes some serious OpenJDK heavyweights (Jim Laskey, Maurizio Cimadamore, Alan Bateman, among others), and the CFV (Call for Votes) passed on the OpenJDK announce list in March. Oracle is now officially proposing it as an OpenJDK project with repos already up on GitHub (detroit, detroit-python).
Helidon → OpenJDK
Oracle is contributing Helidon to OpenJDK and aligning its release cadence with the JDK - meaning Helidon will ship alongside each JDK release and share LTS timelines. This is a notable move: it elevates Helidon from “Oracle’s microservices framework” to a community-governed project with first-class JDK integration.
Waiting for additional details here! As soon I have them, I’ll share 😊
JetBrains Announces Koog for Java
Not all JavaOne news came from Oracle. JetBrains chose the conference to announce Koog for Java - bringing their AI agent framework, originally built in Kotlin, to idiomatic Java with fluent builder-style APIs.
Koog is an open-source framework for building enterprise-ready AI agents on the JVM. What makes it interesting is that it’s not a research project - JetBrains built it to power their own AI features in IntelliJ and other products, then extracted it as a standalone framework. The feature set reads like a wishlist for anyone who’s tried to build reliable agents: graph-based workflow strategies, persistent checkpointing (resume from exactly where you stopped after a crash), intelligent history compression for long-running conversations, Spring Boot integration, MCP support, and observability via OpenTelemetry exporters to Langfuse and W&B Weave.
The Java API launch is particularly well-timed. With Oracle pushing the “Java for AI” narrative hard (see below), and Rod Johnson’s Embabel taking a Spring-native, domain-modeling approach to the same problem space, we’re suddenly seeing a real competition for the JVM agent framework crown. As a recent comparison piece put it: Embabel reasons about goals and conditions (think: declarative planning), while Koog asks you to define a directed graph of nodes (think: LangGraph, but on the JVM). Different philosophies, same goal - making Python optional for the agent layer of your stack.
BTW: Java 26 is already available in IntelliJ IDEA.
The AI Narrative
The keynote’s title alone - “Java for an AI World” - tells you everything about where Oracle’s head is at right now.
Ana-Maria Mihalceanu and Lize Raes - both Oracle Developer Advocates - had a remarkably long segment during the keynote. Together with Paul Sandoz, they covered two angles: the Babylon/HAT stack (from JDK building blocks through GPU-enabled libraries to Java code running on GPUs), and a practical demo of an LLM-powered triage system for a medical appointment helpdesk - automatic ticket classification, urgency flagging, matching against known bugs with relevance scores, and a clear split between what AI handles and where humans stay in control.
The amount of keynote time Oracle gave to these topics says more than any roadmap slide.
Who outside of Oracle team was on the JavaOne Stage
The opening keynote - wasn’t just an Oracle show. Rod Johnson, Josh Long, and engineering leads from Microsoft, NVIDIA, and Uber all shared the stage. That lineup alone tells you something about where the Java ecosystem is headed.
Microsoft came with a concrete developer play: the GitHub Copilot Community SDK for Java, which brings programmatic control of Copilot CLI and its agents into the Java ecosystem — including conversational AI sessions, custom tools, streaming events, and MCP server integration. Their sessions covered building production GenAI systems with LangChain4j and vector search on Azure. Oh, and mark your calendars: Microsoft also invited evereyone to JDConf 2026 (April 8–9), their free virtual Java developer conference, now in its sixth year.
NVIDIA and Ikroop Dhillon had a presence that reflects Java’s growing role in GPU-accelerated workloads. With GTC 2026 running concurrently (literally across town in San Jose), the Java-NVIDIA intersection is Project Babylon territory - extending Java’s reach into AI model training and GPU compute. The broader theme: Java as the orchestration layer for inference pipelines that run on NVIDIA hardware. However, while it was interesting, it was more about Nvidia than Java, with an Apache Solr guest appearing.
Uber presented probably the most hands-on production story at the conference: how they scaled GPU-accelerated inference while maintaining strict tail-latency SLOs in a JVM-centric environment. Their talk covered how Java services integrate with NVIDIA Triton Inference Server to serve models from small neural nets to multi-hundred-gigabyte LLMs, and the JVM tuning rabbit holes that followed. If you want proof that “Java for AI” isn’t just marketing, this is it.
Josh Long , in his trademark style, took the stage to show just how quickly you can go from zero to a working AI-integrated application with Spring Boot 4.0.3 and Spring AI. Starting from Spring Initializr he demoed the new capabilities of the Spring ecosystem, building an app on the spot. He also showed off the OpenAI integration and PassKeys support in Spring Security via a pre-recorded demo — the keynote pace was so relentless that even Josh Long couldn’t live-code everything. And because it’s Josh Long, the whole thing came with Hitchhiker’s Guide to the Galaxy references, because of course it did.
42.
PS: Valhalla Update: Early Access 3 Is Here
On the Valhalla front, things are moving faster than it might seem from the JDK 26 JEP list alone. While JDK 26 ships without any Valhalla features (and the Vector API remains in incubation waiting for them), the Valhalla team has been busy outside the main release train. Just last week, Build 27-jep401ea3+1-1 - the third Early Access build of JEP 401: Value Classes and Objects - was made available, based on an incomplete version of JDK 27.
This is the third EA milestone since the first build dropped in October 2025, and the pace of iteration suggests that JEP 401 is getting closer to targeting a release. The EA build focuses on two key optimizations: heap flattening (reducing the memory footprint of value objects in fields and arrays) and scalarization (avoiding memory allocation in JIT-compiled code). In benchmarks, the results are already impressive - Dan Smith’s original demo showed significant performance improvements for arrays of value objects compared to identity objects.
And a shout-out to the DataLinks crew who are on the ground at JavaOne! Thanks to Michal Niczyporuk for the photo - great to have Polish representation in Redwood Shores.




















