Java21

16 posts in this section

Foreign Function & Memory API (JEP 442): Calling Native Code Without JNI

Preview Feature in Java 21 — Finalized in Java 22 (JEP 454). The API shown here is the Java 21 preview version; it is nearly identical to the final API. Why Replace JNI? Java Native Interface (JNI) has been the standard way to call native code since Java 1.1. It works but is notoriously painful: Requires writing C wrapper code for every native call Native method signatures must exactly match Java declarations (or you get silent crashes) Memory management is manual — leak native memory once and you have a slow memory leak JNI calls disable JIT optimizations around the call site Debugging native crashes through JNI is extremely difficult The Foreign Function & Memory (FFM) API replaces all of this: call native functions directly from Java, manage native memory safely with automatic lifetime management, and do it without writing a single line of C.

Continue reading »

Generational ZGC (JEP 439): Sub-Millisecond Pauses at Any Scale

Why GC Still Matters in 2024 Even with better APIs and faster hardware, garbage collection pauses remain one of the top causes of latency spikes in Java services. A 200ms GC pause in a payment processing service is a customer-visible failure. A 50ms pause in a trading system is a missed execution window. Java 21 delivers Generational ZGC — the most capable GC Java has ever shipped — as a production-ready, non-preview feature.

Continue reading »

Java 21 Production Checklist and Performance Best Practices

The Production Mindset Migrating to Java 21 unlocks new capabilities, but production readiness requires deliberate configuration. The JVM defaults are conservative — designed to work reasonably across a wide range of workloads, not to be optimal for any specific one. This article covers: Which JVM flags to set for every production Java 21 deployment GC selection and tuning for different workload profiles Virtual thread configuration and monitoring Container-aware JVM settings Observability and profiling Startup and memory optimization JVM Flags: The Production Baseline Start every Java 21 production deployment with this baseline flag set:

Continue reading »

Java 21: The LTS Release That Changes Everything

Why Java 21 Is Different Every third Java release is an LTS — Long-Term Support. Java 21 is the fourth LTS after Java 8, 11, and 17. But unlike previous LTS releases, which were largely incremental, Java 21 delivers features that fundamentally change how you write concurrent code, how the JVM manages memory and GC, and how Java competes with dynamic languages for expressiveness. Three years of Project Loom work lands as Virtual Threads — production-ready, requiring zero framework changes for most Spring Boot or Jakarta EE applications.

Continue reading »

Key Encapsulation Mechanism API (JEP 452): Post-Quantum Cryptography in Java

Why Post-Quantum Cryptography Now? Classical public-key cryptography (RSA, ECDH) relies on mathematical problems that are hard for classical computers — factoring large integers or solving the discrete logarithm problem. A sufficiently powerful quantum computer running Shor’s algorithm could solve these problems efficiently, breaking all existing RSA and ECC-based security. Quantum computers capable of breaking 2048-bit RSA don’t exist yet. But “harvest now, decrypt later” attacks are real: adversaries intercept and store encrypted traffic today, planning to decrypt it once quantum computers mature.

Continue reading »

Migrating to Java 21: From Java 8, 11, and 17 — Step by Step

Why Migrate Now? Java 21 is the current Long-Term Support (LTS) release, and it is the most feature-rich LTS since Java 8. LTS releases receive security patches and bug fixes for years. Java 11, the previous widely-used LTS, reached its extended support window end depending on your vendor. Java 8 mainstream support ended in 2019. More concretely, Java 21 brings: Virtual Threads — drop-in replacement for platform threads, enabling massive concurrency without reactive rewrites Pattern Matching for switch and records — eliminating entire categories of verbose, error-prone instanceof/cast chains Sequenced Collections — a unified API for ordered collection types Generational ZGC — sub-millisecond GC pauses at any heap size These are not incremental improvements.

Continue reading »

Pattern Matching for switch (JEP 441): Type Dispatch Without the Boilerplate

The Problem: Cascading instanceof Chains Any Java codebase handling multiple subtypes has code like this: // Java 16 and earlier — the bad old way static double calculateArea(Shape shape) { if (shape instanceof Circle) { Circle c = (Circle) shape; return Math.PI * c.radius() * c.radius(); } else if (shape instanceof Rectangle) { Rectangle r = (Rectangle) shape; return r.width() * r.height(); } else if (shape instanceof Triangle) { Triangle t = (Triangle) shape; return 0.

Continue reading »

Record Patterns (JEP 440): Destructuring Records with Power and Precision

Records Recap Records (Java 16, JEP 395) are transparent carriers of immutable data: record Point(int x, int y) {} record ColoredPoint(Point point, String color) {} record Line(Point start, Point end) {} The compiler generates a constructor, accessor methods (x(), y()), equals, hashCode, and toString. Before Java 21, accessing record components required calling accessor methods: Object obj = new ColoredPoint(new Point(3, 4), "red"); if (obj instanceof ColoredPoint cp) { int x = cp.

Continue reading »

Scoped Values (JEP 446): Thread-Safe Context Without ThreadLocal

Preview Feature — Requires --enable-preview at compile and runtime. The ThreadLocal Problem at Scale ThreadLocal has been the standard way to pass context (request ID, user session, database transaction) implicitly through a call stack without threading it through every method signature. It works well with a few hundred platform threads. With virtual threads, it breaks down. Problem 1 — Memory overhead with inheritance When you create a child thread with InheritableThreadLocal, Java copies the thread-local map from parent to child:

Continue reading »

Sequenced Collections (JEP 431): A Unified API for Ordered Collections

The 30-Year Gap in the Collections API Java’s Collections Framework has a fundamental inconsistency: there is no uniform way to access the first or last element of an ordered collection. Before Java 21: // List — index-based var list = List.of("a", "b", "c"); String first = list.get(0); // first element String last = list.get(list.size() - 1); // last element — verbose, error-prone // Deque — special methods Deque<String> deque = new ArrayDeque<>(List.

Continue reading »