Java 26 — All New Features, Removals & Previews
Consider becoming a paid subscriber for as low as $1.6/mo (with an annual subscription) and support the work :)
Still not convinced? Check out the details of the past work
Java 26 adds a new version enum:
HttpClient.Version.HTTP_3This allows
HttpClientto negotiate and use HTTP/3. HTTP/3 is not an evolution of HTTP/2 over TCP.It uses a completely new transport.HTTP/3 uses QUIC over UDP → not upgradable from HTTP/1.1 or HTTP/2.
Connection-level version negotiation is non-trivial.
API surface change is tiny; complexity is under the hood.
HttpClient client = HttpClient.newBuilder() .version(HttpClient.Version.HTTP_3) .build();
When to use
Latency-sensitive apps.
Packet-loss-heavy networks (QUIC handles loss better).
Services that already support HTTP/3 (e.g., Cloudflare, Google).
Prepare to Make Final Mean Final
Its main goal is to restore the “immutability guarantee” of
finalfields by default. In other words, make it so that once afinalfield is assigned (in a constructor or static initializer), it can’t be overwritten via reflection and related mechanisms.In Java, since JDK 5, “deep reflection” — using
java.lang.reflect.Field.setAccessible(true)+Field::set(...)— has allowed code to override thefinalguarantee: even afinalfield can be changed at runtime.That undermines the semantic meaning of
final: for correctness, reasoning about immutability, thread-safety, etc. Also undermines certain optimizations (like constant-folding) the JVM might perform under the assumption thatfinalfields don’t change.JEP 500 considers the fact that allowing such unconstrained mutation was a “poor choice” and wants to align with the stricter immutability model already used for newer constructs (e.g.
records, hidden classes, etc.)From JDK 26, by default, if code uses reflection (or other deep reflection APIs) to mutate a
finalfield, the JVM will now emit a warning at runtime (instead of silently allowing it).The warning is intended to notify developers of code paths that mutate final fields, to give time to migrate.
In future JDK versions, the plan is for such mutation to be disallowed by default — i.e.
Field::set(...)on a final field will throw an exception rather than succeed (unless explicitly allowed)
JEP 504 proposes to remove the entire java.applet API from the standard Java SE platform.
It was marked Completed and targeted for JDK 26.
The Applet API was deprecated for removal back in JDK 17 (2021).
Web browsers no longer support Java applets — the plugin model that allowed applets to run in browsers is largely dead.
Lazy Constants (Second Preview)
JEP 526 introduces a new API: java.lang.LazyConstant<T> — a holder for a value that is computed lazily (on first demand) but then becomes immutable (“constant”) thereafter.
Lazy constants are treated by the JVM as “true constants,” enabling many of the same performance and optimization benefits that
finalfields enjoy (constant-folding, inlining, etc.) once initialized.Compared to a plain
finalfield, lazy constants give flexibility in when initialization happens — instead of requiring initialization at construction or class-load time.Using
finalfields give immutability — butfinalforces eager initialization (at object creation or class initialization).
In many real-world cases (e.g., heavy resources: loggers, configs, caches, service clients,) you may want to delay initialization until first use to save startup costs.private static final LazyConstant<Logger> LOG = LazyConstant.of(() -> Logger.create(MyService.class));JEP 526 is a refinement / second preview of what had been previously proposed under JEP 502 (“Stable Values”). Changes include:
Renamed the API from
StableValue→LazyConstant— a name better aligned with the high-level use case.Removed lower-level methods (
orElseSet,setOrThrow,trySet) from the API — simplifying it to just “factory + get” style.
Primitive Types in Patterns, instanceof, and switch (Fourth Preview)
JEP 530 makes primitive types (int, long, float, double, boolean, etc.) first‑class participants in Java’s pattern matching,
instanceof, andswitchIt’s a preview language feature in JDK 26.
Historically, pattern matching,
instanceof, andswitchsupported only reference types (objects), or a limited subset of primitive-like types; this JEP removes that restriction.Primitive Type Patterns in
instanceof,switch, Pattern MatchingYou can now write:
if (x instanceof int i) { // i is bound as int } switch (someLongValue) { case 1L -> ... case long l -> ... }instanceofSupports Primitive TypesInstead of only
instanceof SomeClass, you can test primitive‑to‑primitive safe conversions:int i = ...; if (i instanceof byte b) { // tests if i can be losslessly cast to byte // b is byte }switchWorks on All Primitive Types
Structured Concurrency (Sixth Preview)
JEP 525 proposes a new API for structured concurrency in Java — grouping related concurrent tasks (sub‑tasks) into a single larger “unit of work,” rather than letting each thread/future run independently.
The goal: simplify concurrent programming, improve error handling and cancellation, make concurrency more reliable and observable.
This is the sixth preview (i.e. still not “final” / fully stable) — meaning: available in JDK 26, but API and semantics might evolve.
Example code:
Scope cancels remaining tasks automatically if any task fails.
ShutdownOnFailureensures clean error handling.No manual thread pool management.
Ahead-of-Time Object Caching with Any GC
JEP 516 extends the existing Ahead‑Of‑Time (AOT) cache (from earlier “class loading & linking ahead‑of-time” support) so that cached Java objects (not just classes) can be used with any garbage collector — including low‑latency ones like ZGC.
In previous JDKs, AOT cache stored objects in a GC‑specific binary layout; that meant the cache only worked reliably with certain GCs (Serial, Parallel, G1). That prevented using AOT cache + ZGC simultaneously.
Now, the cache can optionally use a new GC-agnostic format: instead of mapping memory directly, the JVM will stream and materialize objects at startup. That means regardless of the active garbage collector, the cache can still be used.
JEP 522 — G1: Improve Throughput by Reducing Synchronization
JEP 522 aims to improve throughput and latency for applications using G1 by reducing the synchronization overhead between application (mutator) threads and GC threads.
It changes the write‑barrier / card‑table mechanism inside G1, replacing the old heavily synchronized approach with a dual‑card‑table + swap strategy — letting application threads update one card table lock‑free while GC/optimizer threads process the other
PEM Encodings of Cryptographic Objects (Second Preview)
JEP 524 adds a new, standardized API for converting Java crypto objects (keys, certificates, CRLs, etc.) to and from the textual PEM format — the classic Base64 + header/footer format used widely in TLS, SSH, cert files, etc.
The API is a preview in JDK 26 (second preview) — meaning you must opt in with preview flags to use it.
Historically, if you had a certificate or key in Java (like
X509Certificate,PrivateKey,PublicKey, etc.) and wanted to export it as PEM (to write to file, send over network, interoperate with OpenSSL/SSH/other systems), there was no built-in Java API — you had to manually base64‑encode DER or use external libraries.PEM is extremely widely used (TLS certs, key stores, SSH, config files, certificates, CRLs, etc.). By adding native PEM support, Java becomes far more interoperable and convenient for security, devops, tooling, and integration workflows
Consider becoming a paid subscriber for as low as $1.6/mo (with an annual subscription) and support the work :)
Still not convinced? Check out the details of the past work
Check out more Java/Spring Boot Interview Coding Questions






Really solid compilation of what's coming in 26. JEP 522's reduced synchronization for G1 is particualrly interesting because throughput gains often come at latency costs, but this one seems to tackle both. The dual card table approach is clever, letting mutators run mostly lock-free while GC scans the alternate set. I'm curiuos though, for workloads with extremely high allocation rates, does the swap overhead between tables become noticeable, or is it mostly negligible under typical production scenarios?