Javajavajdk-27post-quantum-cryptographytlsg1-gcjvmcompact-object-headersjfrstructured-concurrency

JDK 27: Four Zero-Code Wins, Headlined by Post-Quantum TLS

JDK 27 ships September 15, 2026. Four final JEPs change every Java process with zero code changes — headlined by post-quantum TLS. Here's what matters.

August 31, 2026
7 min read

JDK 27 looks like a quiet release. Nine JEPs, no LTS badge, and no single feature that reorders the universe the way HTTP/3 did in 26. If you skimmed the list and moved on, I wouldn't blame you.

I think that read is wrong. JDK 27 is the release where Java stops asking you to opt in to good defaults and simply turns them on. Four of the nine JEPs ship final, and all four change the behavior of every Java process that upgrades — with zero lines of code changed. One of them quietly makes Java one of the first mainstream runtimes to defend against quantum computers by default. General availability is September 15, 2026. Here's what's actually in it, ordered by how much it matters.

First, what JDK 27 is (and isn't)

JDK 27 is a short-term, non-LTS feature release — six months of Oracle support, the second non-LTS since the JDK 25 LTS landed in September 2025 (JDK 26 was the first). The next LTS won't arrive until JDK 29 in 2027. It's currently in the Release Candidate phase with the feature set frozen, on schedule for GA on September 15, 2026.

Here's the full manifest, so you can see the shape of the release at a glance:

JEPFeatureStatus
527Post-Quantum Hybrid Key Exchange for TLS 1.3Final
534Compact Object Headers by DefaultFinal
523Make G1 the Default Garbage Collector in All EnvironmentsFinal
536JFR In-Process Data RedactionFinal
538PEM Encodings of Cryptographic ObjectsThird preview
531Lazy ConstantsThird preview
532Primitive Types in Patterns, instanceof, and switchFifth preview
533Structured ConcurrencySeventh preview
537Vector APITwelfth incubator

Four final, five still baking. The finals are the story — they're all defaults that flip the moment you upgrade. Let's start with the one that matters most.

The Headline: Post-Quantum TLS, On by Default (JEP 527)

If there's a single reason to pay attention to JDK 27, this is it. Public-key cryptography — RSA, ECDH — is what keeps your TLS sessions secret, and a sufficiently large quantum computer will break it. That machine doesn't exist yet, but that's not the point. The attack that matters today is harvest now, decrypt later: an adversary records your encrypted traffic now, stores it, and decrypts it years from now once the hardware catches up. If your data needs to stay confidential for more than a few years, the clock is already running.

JDK 27's answer is hybrid key exchange, wired straight into the TLS 1.3 handshake and enabled by default — no code changes, no provider configuration. A hybrid scheme pairs a battle-tested classical algorithm with a quantum-resistant one, and the session stays secret as long as either survives:

The JDK ships three hybrid schemes, each combining ML-KEM with ephemeral elliptic-curve Diffie-Hellman: X25519MLKEM768 (the default, placed at the front of the client's preference list), SecP256r1MLKEM768, and SecP384r1MLKEM1024. This is the payoff of a multi-release build-up — the KEM API arrived in Java 21 (JEP 452), the ML-KEM algorithm in Java 24 (JEP 496), and now JDK 27 connects them to TLS.

For most services this is invisible, which is exactly the point. You get to override it if you need to — reorder or pin schemes via the jdk.tls.namedGroups system property, or per-socket with SSLParameters::setNamedGroups:

java
SSLParameters params = socket.getSSLParameters();
params.setNamedGroups(new String[] {
    "SecP256r1MLKEM768", "X25519MLKEM768", "secp256r1", "x25519"
});
socket.setSSLParameters(params);

Two caveats worth knowing. Hybrid key shares are larger than classical ones, so expect a modest bump in handshake size. And this only covers TLS 1.3 key exchange via javax.net.ssl — it doesn't touch your stored data or your signatures. It's a big, genuinely important step, not the whole post-quantum journey.

Free Heap: Compact Object Headers Become the Default (JEP 534)

Every object on a 64-bit JVM carries a header, and until now that header was 96 bits. JEP 534 makes compact object headers the default layout, packing the same information into 64 bits:

You may recognize this one — it shipped as an opt-in flag in JDK 25 (JEP 519) after an experimental run in 24, and it's been hardened at serious scale since (Amazon ran it across hundreds of services via a JDK 17 backport). On SPECjbb2015 the JVM team measured roughly 22% less heap, 8% less CPU time, and 15% fewer collections; real-world expectations are a more conservative but still meaningful 10–20% heap reduction on object-heavy workloads. Caches, map-heavy services, JSON trees, and graph structures feel it most.

This is the rare release where you do less and get more: upgrade, change nothing, and your heap shrinks. If something breaks — unlikely, but possible with low-level tooling that pokes at object layout — -XX:-UseCompactObjectHeaders restores the old behavior. I covered the opt-in version in my Java 25 LTS breakdown; the only difference now is that you no longer have to ask for it.

G1 Becomes the Default Everywhere (JEP 523)

Since JDK 9, G1 has been the default garbage collector — but only on server-class machines. On constrained environments (roughly one CPU or less than ~1792 MB of memory) the JVM quietly picked the Serial collector instead. That meant a Lambda function or a small container could behave differently from the same code running on a beefy host.

JEP 523 ends that split. From JDK 27, if you don't specify a collector, you get G1 — regardless of cores or memory. The justification is that G1 has steadily closed the gap (JEP 522's synchronization reductions brought its max throughput close to Serial's), while its latency was always better thanks to incremental old-generation collection.

For most server deployments this changes nothing — G1 was already your default. Where it matters:

  • Constrained environments (Lambda, small containers) that previously got Serial will now get G1. Usually an improvement, but if you've tuned around Serial's predictable behavior in tight memory limits, re-benchmark before you upgrade.
  • Flag hygiene. Explicit -XX:+UseG1GC lines are now redundant — clean them up. The AlwaysActAsServerClassMachine / NeverActAsServerClassMachine flags lose most of their purpose and are deprecated for removal.
  • One real gotcha. With G1 as the default, MinHeapFreeRatio moves from 40 to 0 and MaxHeapFreeRatio from 70 to 100, which effectively disables heap resizing driven by those ratios. If your GC tuning assumed the old defaults, check it.

The escape hatch is unchanged: -XX:+UseSerialGC still does exactly what it says. This only changes the implicit choice.

JFR Stops Leaking Your Secrets (JEP 536)

This is the unglamorous one that everybody benefits from. JDK Flight Recorder captures, among other things, your command-line arguments, the initial values of environment variables, and system properties — which is exactly where API keys, database passwords, and tokens tend to live when they're passed via -D... or env vars. JFR files get shipped to vendors, attached to support tickets, and dropped in shared buckets more often than anyone admits.

JEP 536 lets JFR redact that sensitive data in-process, before the recording is finalized — so the secrets never make it to disk in the first place. New -XX:FlightRecorderOptions settings (redact-key and redact-argument) give you control over what's masked. It's defense-in-depth, not a replacement for keeping secrets out of arguments in the first place — but it closes a hole that's bitten more teams than will say so publicly.

The Five Still Cooking

Half the release is preview or incubator — worth knowing, not worth building production on yet:

  • Lazy Constants, third preview (JEP 531). The feature formerly known as StableValue gives you "deferred immutability": a value initialized at most once, on demand, that the JVM can still constant-fold like a final. It fills the gap between eager final fields and the double-checked-locking gymnastics we use to avoid them. This round removes isInitialized()/orElse() and adds Set.ofLazy(...), completing lazy List, Set, and Map:

    java
    private final LazyConstant<Logger> logger =
        LazyConstant.of(() -> Logger.create(OrderController.class));
     
    void submitOrder(User user) {
        logger.get().info("order submitted"); // computed on first call, at most once
    }
  • Primitive Types in Patterns, fifth preview (JEP 532). Pattern matching extends to primitives, so case int i when i > 100 -> ... works without boxing. No changes from the fourth preview — it's stable, just waiting to finalize.

  • Structured Concurrency, seventh preview (JEP 533). StructuredTaskScope treats a group of related subtasks as one unit of work — fork them, and if one fails the scope cancels the rest. It changed again this round (awaitAll() is gone; joiners now throw ExecutionException), so if you prototyped on an earlier preview, expect to update. We cover the concurrency model it builds on in the Java concurrency guide.

  • Vector API, twelfth incubator (JEP 537). Express vector math in plain Java and let the JIT compile it to SIMD (AVX, NEON, SVE). Still waiting on Project Valhalla before it can graduate.

  • PEM Encodings, third preview (JEP 538). A standard API to encode and decode keys, certificates, and CRLs in PEM format — the thing you've been doing with BouncyCastle's PEMParser/PEMWriter or hand-rolled Base64. Slated to finalize in JDK 28 as JEP 542.

A pattern worth naming: several of these previews are being held for Project Valhalla. The next LTS (JDK 29) is the realistic target for most of them to cross the finish line.

What I'd Do About It

Because JDK 27 is non-LTS, most enterprises standardized on JDK 25 won't rush to it — and that's fine. But the four final features are conservative, well-tested, and worth validating against your workload now, even if you adopt later:

  1. Grab an early-access build (jdk.java.net/27, or sdk install java 27.ea-open on SDKMAN) and run your test suite.
  2. If you run constrained environments — Lambda or containers below ~1 CPU / 1792 MB — verify G1's behavior there and re-check any tuning that assumed the old MinHeapFreeRatio/MaxHeapFreeRatio defaults.
  3. If you use JFR, confirm redaction is additive for your recordings and that nothing you depend on got masked.
  4. If you prototyped the previews on 25 or 26 — especially structured concurrency — budget for the API changes.
  5. If you handle long-lived confidential data, start planning for post-quantum TLS now; JDK 27 gives you the transport layer for free.

If you're on JDK 25 LTS and stable, stay put and aim for JDK 29. If you track the latest releases, 27 is a safe, rewarding hop — arguably the best "free wins" release in years. For the fundamentals underneath all of this, the Java roadmap and the backend engineering guide are the place to start.

The Bottom Line

JDK 27 isn't flashy, and that's the point. It's the release where Java's good defaults stop being opt-ins: post-quantum TLS on by default, G1 everywhere, object headers shrunk for free, and JFR no longer writing your secrets to disk. None of it asks you to change a line of code. The previews keep inching toward Valhalla, but the four finals are reason enough to pay attention — this is the release that quietly hardens and shrinks every JVM you upgrade to it.

References

More from Java

Browse more articles and guides on this topic.