Tutorial

264 posts in this section

AOT Compilation in Java 25 (JEP 514 & 515): Faster Startup, Zero Warm-Up

The Java Startup Problem Java’s performance story has always had one weak spot: startup time. When a JVM starts, it: Loads and verifies class bytecode Interprets bytecode (slow) Profiles which methods are called most (warm-up) Compiles hot methods to native code via JIT (takes time and CPU) Eventually reaches peak throughput This process takes seconds for large applications. For a Spring Boot application, typical warm-up to peak throughput can take 10–30 seconds.

Continue reading »

Compact Object Headers (JEP 519): 33% Less Heap Overhead

What Is an Object Header? Every single Java object — every String, every Integer, every record, every array — carries a header that the JVM uses for bookkeeping. Your code never sees this header; it lives alongside the object’s fields in memory. Before Java 25, on a 64-bit JVM, the header occupied 96 to 128 bits (12–16 bytes): ┌─────────────────────────────────────────────────────────┐ │ Mark Word (64 bits) │ │ ─ identity hash code │ │ ─ lock state (biased lock / thin lock / fat lock) │ │ ─ GC age bits │ ├─────────────────────────────────────────────────────────┤ │ Class Pointer (32 bits compressed / 64 bits full) │ │ ─ pointer to the object's class (Klass* in HotSpot) │ └─────────────────────────────────────────────────────────┘ With UseCompressedOops (default), the class pointer is compressed to 32 bits, giving a 96-bit (12-byte) header.

Continue reading »

Compact Source Files & Instance Main Methods (JEP 512): Java as a Scripting Language

The Ceremony Problem When a student writes their first Java program, they copy this boilerplate: public class HelloWorld { public static void main(String[] args) { System.out.println("Hello, World!"); } } Three layers of ceremony for one line of logic: A public class whose name must match the filename A public static void main(String[] args) signature with specific keywords The actual code, buried inside two levels of braces This has been the #1 on-ramp friction point in Java for 30 years.

Continue reading »

Flexible Constructor Bodies (JEP 513): Validate Before super()

The Old Rule That Caused So Much Pain From Java 1.0 through Java 24, a constructor that extended another class had one rigid rule: super(...) or this(...) must be the first statement in the constructor body. This was enforced by the compiler. Not because of a deep technical reason — but because the JVM specification had always required that the superclass be fully initialized before the subclass could do anything with the object.

Continue reading »

Generational Shenandoah (JEP 516): Best GC for Low Latency

GC Background: Why Generations Matter The Generational Hypothesis is the foundation of most modern GC design: Most objects die young. In a typical Java application, the vast majority of objects are short-lived: request/response objects, DTOs, builder instances, stream pipeline intermediates. They are created, used briefly, and then immediately eligible for collection. A GC that knows about this pattern can be far more efficient than one that treats all objects equally:

Continue reading »

Java 25 Security: Key Derivation Function API & PEM Encodings

Overview Java 25 ships two important security additions: JEP 510 — Key Derivation Function (KDF) API — Final. A standard API for HKDF, PBKDF2, and other KDFs. JEP 470 — PEM Encodings of Cryptographic Objects — Preview. Read and write .pem files without third-party libraries. These fill two long-standing gaps: Java had the underlying crypto but no clean standard API for key derivation and PEM I/O. Part 1: Key Derivation Function API (JEP 510) What Is Key Derivation?

Continue reading »

Java 25: The LTS That Graduates Four Years of Previews

Why Java 25 Matters Java 25 was released on September 16, 2025 — exactly two years after Java 21, following the cadence Oracle committed to when it moved to a two-year LTS cycle. But Java 25 is not just “Java 21 with more stuff”. It is the release where four years of preview work finally becomes production API. Features that Java developers have been testing since Java 21 — Scoped Values, Flexible Constructor Bodies, Module Import Declarations, Compact Source Files — all graduate to final status.

Continue reading »

Module Import Declarations (JEP 511): One Import to Rule Them All

The Problem: Import Hell Every Java developer has experienced this. You open a file and before you see a single line of business logic, you wade through a wall of imports: import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.

Continue reading »

Scoped Values (JEP 506): The Final ThreadLocal Replacement

The ThreadLocal Problem ThreadLocal has been the standard way to pass contextual data through a call chain without polluting method signatures since Java 1.2. Every Java developer has seen it used for things like: Web request context (user ID, correlation ID, tenant ID) Database transaction binding Security principal propagation Logging MDC (Mapped Diagnostic Context) Here is the classic pattern: public class RequestContext { // ThreadLocal stores one value per thread private static final ThreadLocal<String> CURRENT_USER = new ThreadLocal<>(); public static void set(String userId) { CURRENT_USER.

Continue reading »

@MappedSuperclass: Sharing Fields Without Inheritance Tables

Introduction Almost every entity in a real application shares a few common fields: id, createdAt, updatedAt, and perhaps version. Writing these in every entity class is repetitive and error-prone. @MappedSuperclass lets you define them once in a base class that all entities extend — without creating a parent table or any inheritance mapping in the database. What Is @MappedSuperclass? @MappedSuperclass marks a class whose field mappings are inherited by subclass entities.

Continue reading »