Ten JEPs. Five That Matter Right Now.

Java 26 shipped on March 17, 2026. It is the first non-LTS release after Java 25 and it brings ten JEPs to the table. Most coverage fixates on the preview features. That is a mistake. The real story for enterprise teams is the production-ready work: HTTP/3 baked into the standard library, a faster G1 garbage collector, ahead-of-time caching that works with every GC, and the first serious steps toward post-quantum cryptography.

If you are running Java 25 in production, upgrading is straightforward. If you are still on Java 21 or earlier, several of these features stack on top of what Java 25 already delivered, and the cumulative case for moving is getting hard to ignore.

Here is what actually matters, why your engineering leadership should care, and what to watch out for during migration.

HTTP/3 Support in the Standard Library (JEP 517)

This one has been a long time coming. Java’s HttpClient now speaks HTTP/3 natively. No third-party QUIC libraries. No Netty plugins. Just set the version and go.

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

var client = HttpClient.newBuilder()
    .version(HttpClient.Version.HTTP_3)
    .build();

var request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.example.com/orders"))
    .GET()
    .build();

var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());

HTTP/3 runs on QUIC, which uses UDP instead of TCP. The practical difference: better performance on lossy networks, faster connection establishment, and no head-of-line blocking across multiplexed streams. If your services talk to CDNs, external APIs, or mobile clients over unreliable connections, this is a measurable win.

The fallback behavior is sensible. If the server does not support HTTP/3, the client drops to HTTP/2, then HTTP/1.1. Your existing code keeps working. You just get faster connections where the infrastructure supports it.

What This Means for the Business

For teams running microservices that call external APIs, HTTP/3 reduces tail latency on flaky network paths. That translates directly to better p99 response times for end users. If you are operating globally with services spread across regions, the QUIC transport eliminates TCP’s slow-start penalty on high-latency links.

Engineering leaders should note: this is a zero-risk upgrade path. The automatic fallback means you can enable HTTP/3 across services without coordinating server-side changes.

G1 GC Throughput Gains (JEP 522)

G1 has been the default garbage collector since Java 9. JEP 522 makes it meaningfully faster by reducing the synchronization overhead between your application threads and the GC.

The numbers: write barriers drop from roughly 50 instructions to 12 on x64 architectures. In workloads that heavily modify object references, throughput improves 5-15%.

# No new flags required. G1 improvements are automatic in Java 26.
java -XX:+UseG1GC \
     -Xmx8g \
     -Xlog:gc*:file=gc.log:time,uptime,level,tags \
     -jar your-service.jar

# Compare GC logs between Java 25 and Java 26 runs
# Look for reduced pause times and lower GC overhead percentage

The key detail: these gains require no configuration changes. If you are already on G1, you get faster throughput by upgrading the JDK. That is it.

Where You See the Difference

Services that create and discard large object graphs benefit the most. Think order processing pipelines, batch jobs that build up complex data structures, or anything doing heavy serialization and deserialization. The reduced write barrier overhead means your application threads spend less time coordinating with the collector and more time doing actual work.

// This kind of code benefits directly from JEP 522.
// Heavy reference modification with large object graphs.
public class OrderProcessor {

    public ProcessingResult processBatch(List<Order> orders) {
        var results = new ArrayList<OrderResult>(orders.size());

        for (var order : orders) {
            // Each iteration creates temporary objects, modifies references
            var validated = validateOrder(order);
            var enriched = enrichWithInventory(validated);
            var priced = applyPricing(enriched);
            results.add(finalize(priced));
        }

        return new ProcessingResult(results);
    }
}

For engineering leaders: if your cloud bill includes a lot of CPU-bound Java services, and you are already on G1, this is free throughput. No code changes, no tuning, no risk. Just a JDK bump.

AOT Caching With Any Garbage Collector (JEP 516)

Java 25 introduced ahead-of-time class loading and linking. Java 26 extends that AOT cache to work with any garbage collector, including ZGC.

This is a bigger deal than it sounds. Previously, if your team chose ZGC for its sub-millisecond pause times, you could not also use AOT caching to speed up startup. Now you can have both.

# Step 1: Create an AOT cache during a training run
java -XX:+UseZGC \
     -XX:AOTCacheRecord=myapp.aot \
     -jar your-service.jar

# Run representative traffic against the app to warm up caches

# Step 2: Deploy with the cache for faster startup
java -XX:+UseZGC \
     -XX:AOTCache=myapp.aot \
     -jar your-service.jar

The implementation stores cached objects in a GC-agnostic format using logical indices instead of raw memory addresses. At startup, a background thread materializes these objects into the heap. The result: faster startup across all collector configurations.

Why This Matters for Kubernetes and Autoscaling

If you run Java services in Kubernetes with horizontal pod autoscaling, startup time directly impacts how fast you can respond to traffic spikes. A service that takes 8 seconds to reach peak performance instead of 3 seconds means 5 extra seconds of degraded response times every time a new pod comes online.

With JEP 516, teams that chose ZGC for latency-sensitive workloads no longer have to sacrifice startup speed. You get both.

// Verify AOT cache is loaded at startup
public class StartupValidator {

    public static void main(String[] args) {
        long start = System.nanoTime();

        // Application initialization
        var context = SpringApplication.run(MyApplication.class, args);

        long elapsed = (System.nanoTime() - start) / 1_000_000;
        System.out.printf("Application ready in %d ms%n", elapsed);

        // With AOT cache: typically 40-60% faster time-to-ready
        // Without: standard JIT warmup applies
    }
}

Compact Object Headers Moving Toward Default

JEP 519 landed in Java 25 and reduced object headers from 12 bytes to 8 bytes. In Java 26, there is a draft JEP to make compact headers the default. They are not default yet, but the trajectory is clear.

If you have not turned them on, now is the time to start testing. The impact is real: 10-20% memory reduction in workloads with millions of small objects. Oracle’s benchmarks show 15% fewer garbage collections in SPECjbb2015.

# Enable compact object headers (still opt-in for now)
java -XX:+UseCompactObjectHeaders \
     -Xmx4g \
     -jar your-service.jar

# Monitor heap usage before and after
jcmd $(pgrep -f your-service) VM.native_memory summary

If you are already running compact headers on Java 25, nothing changes. If you have not tried them yet, Java 26 is the release to do it. The feature has had another six months of hardening, and it is clearly headed toward being the default. Get ahead of it.

For more on the memory and CPU impact, see our Java 25 performance deep dive.

Post-Quantum Cryptography: JAR Signing and HPKE

Java 26 adds two security features that will not matter to most teams today but will matter to everyone within a few years.

First, you can now sign JARs with ML-DSA (Module-Lattice-Based Digital Signature Algorithm), a quantum-resistant signature scheme standardized by NIST. This is the algorithm designed to survive attacks from future quantum computers.

# Sign a JAR with the ML-DSA post-quantum algorithm
jarsigner -keystore mykeys.p12 \
          -sigalg ML-DSA-65 \
          -signedjar signed-app.jar \
          app.jar mykey

Second, Java 26 adds Hybrid Public Key Encryption (HPKE), defined in RFC 9180. HPKE combines a key encapsulation mechanism (KEM), a key derivation function (KDF), and authenticated encryption (AEAD) into a single, standardized API.

The “Harvest Now, Decrypt Later” Problem

Here is why this matters even though practical quantum computers are years away. Adversaries can capture encrypted traffic today and store it. When quantum computers become viable, they can decrypt that stored data. If your organization handles data with a long confidentiality window (financial records, health data, government contracts), the time to start transitioning is now.

Java 26 does not force you to change anything. But it gives you the building blocks. Teams working in regulated industries or handling sensitive long-lived data should start evaluating these APIs.

For engineering leaders: post-quantum readiness is increasingly showing up in compliance requirements and RFPs. Having your platform on a JDK that supports these algorithms is a checkbox you want to have filled.

Structured Concurrency: Sixth Preview (JEP 525)

Structured concurrency is still in preview, but each iteration gets closer to final. The API treats a group of concurrent tasks as a single unit of work, which makes error handling and cancellation dramatically simpler.

import java.util.concurrent.StructuredTaskScope;

OrderDetails fetchOrderDetails(long orderId) throws Exception {
    try (var scope = StructuredTaskScope.open()) {

        var order = scope.fork(() -> orderService.findById(orderId));
        var customer = scope.fork(() -> customerService.findByOrderId(orderId));
        var inventory = scope.fork(() -> inventoryService.checkForOrder(orderId));

        scope.join();

        return new OrderDetails(
            order.get(),
            customer.get(),
            inventory.get()
        );
    }
    // If any subtask fails, the others are automatically cancelled.
    // No leaked threads. No dangling futures.
}

If you have been waiting for structured concurrency to finalize before adopting it, keep waiting. But start prototyping with it on non-production code. When it goes final (likely Java 27 or 28), teams that have already experimented will move faster.

Other Changes Worth Knowing About

Primitive Types in Patterns (JEP 530, Fourth Preview)

Pattern matching now handles primitive types in instanceof and switch. This eliminates a lot of manual casting and boxing code.

// Before: manual type checking and casting
Object value = getMetricValue();
if (value instanceof Integer i) {
    processInt(i);
} else if (value instanceof Double d) {
    processDouble(d);
}

// Java 26 preview: primitives work directly in patterns
switch (getMetricValue()) {
    case int i    -> processInt(i);
    case double d -> processDouble(d);
    case String s -> processString(s);
}

Lazy Constants (JEP 526, Second Preview)

Lazy constants let you defer expensive initialization until first access while still getting the JVM optimizations that final fields provide. Useful for configuration values, service clients, and caches that should not initialize at class load time.

Final Field Mutation Warnings (JEP 500)

Java 26 now warns when code uses deep reflection to mutate final fields. This is a signal: a future release will make final truly immutable. If you have libraries or frameworks that reflectively modify final fields, start looking for alternatives now.

Applet API Removal

The Applet API is gone. It was deprecated for removal in Java 17. If this affects you, you have had five years of warnings.

Migration Considerations

Coming From Java 25

This is a minor upgrade. Java 26 is a non-LTS release, so it gets six months of support. If you are on Java 25 LTS, the decision comes down to whether specific features (HTTP/3, G1 throughput, AOT with any GC) justify the move to a short-term release.

For most enterprise teams, the pragmatic call is to test against Java 26 and cherry-pick the features that matter for your workload. When Java 27 ships in September 2026, evaluate again.

Coming From Java 21 or Earlier

The cumulative improvements from Java 21 to Java 26 are substantial: virtual threads (finalized in 21), compact object headers (25), Generational Shenandoah (25), and now HTTP/3 and G1 throughput gains (26). See our Java 25 enterprise migration guide for the upgrade path.

If you are still on Java 8 or 11, the migration is bigger but the payoff is proportionally larger. Our complete guide to migrating from Java 8 to 17 covers the foundational steps.

What to Test Before Upgrading

  1. Run your test suite on Java 26. Most applications work without changes. The ones that break usually depend on removed APIs (Applet, Thread.stop()) or reflective access to JDK internals.

  2. Check for final field mutation warnings. Run your application and grep logs for the new warnings. Fix these before they become errors in a future release.

  3. Benchmark G1 throughput. Compare GC logs between your current JDK and Java 26. The improvement should be visible without any tuning changes.

  4. Test compact object headers if you have not already. Enable -XX:+UseCompactObjectHeaders in staging and measure memory usage. It is heading toward default, so you want to know how your application behaves.

# Quick smoke test for Java 26 compatibility
java -version  # Confirm JDK 26

# Run with verbose deprecation and removal warnings
java --illegal-access=warn \
     -Xlint:all \
     -jar your-service.jar

# Check for final field mutation warnings
java -jar your-service.jar 2>&1 | grep -i "final field"

The Bottom Line

Java 26 is not a flashy release. It is a solid one. The HTTP/3 support, G1 throughput improvements, and expanded AOT caching are production-grade features that reduce latency, cut cloud costs, and improve startup times with minimal migration effort.

The post-quantum cryptography work is forward-looking but important. The final field warnings are a clear signal about where the platform is headed.

For teams on Java 25 LTS, there is no rush to move. But there are good reasons to test. For teams on older versions, the gap keeps widening. Every six months, the case for staying on Java 11 or 17 gets weaker.

If your team needs help planning a Java upgrade or wants to benchmark these features against your specific workload, we can help. We have done this work for organizations running everything from monolithic Spring applications to distributed microservice architectures. The migration path is well-understood at this point. It is just a matter of doing the work.

Java Modernization Readiness Assessment

15 questions your team should answer before starting a migration. Takes 10 minutes. Could save you months.