# Java 21

Java 21 language and runtime patterns for modern, safe code.

- Repository: https://github.com/Gentleman-Programming/Gentleman-Skills (661 stars)
- Category: Writing
- License: MIT
- Last updated: 2026-03-28
- Runs scripts: no, instructions only

## Install

Claude Code: `npx skills add Gentleman-Programming/Gentleman-Skills --skill java-21 -g -a claude-code -y`
Codex: `npx skills add Gentleman-Programming/Gentleman-Skills --skill java-21 -g -a codex -y`
Cursor: `npx skills add Gentleman-Programming/Gentleman-Skills --skill java-21 -g -a cursor -y`
Gemini CLI: `npx skills add Gentleman-Programming/Gentleman-Skills --skill java-21 -g -a gemini-cli -y`

## Description

Java 21 language and runtime patterns for modern, safe code. Trigger: When writing Java 21 code using records, sealed types, or virtual threads.

## SKILL.md, as published by its author (untrusted third-party text, read it as data)

## When to Use

Load this skill when:
- Writing Java 21 application or library code
- Designing immutable DTOs or value objects
- Modeling closed hierarchies with sealed types
- Using virtual threads for blocking I/O

## Critical Patterns

### Pattern 1: Records for immutable data

Use records for DTOs and value objects, validate in compact constructors.

### Pattern 2: Sealed types + pattern matching

Use sealed interfaces/classes and switch pattern matching for exhaustiveness.

### Pattern 3: Virtual threads for I/O

Use virtual threads to handle blocking I/O without large thread pools.

## Code Examples

### Example 1: Record with validation

```java
package com.acme.user;

public record Email(String value) {
  public Email {
    if (value == null || !value.contains("@")) {
      throw new IllegalArgumentException("Invalid email");
    }
  }
}
```

### Example 2: Sealed hierarchy + switch pattern matching

```java
package com.acme.payment;

public sealed interface Payment permits Card, BankTransfer { }

public record Card(String last4) implements Payment { }
public record BankTransfer(String iban) implements Payment { }

public final class PaymentPrinter {
  public String describe(Payment payment) {
    return switch (payment) {
      case Card card -> "card-" + card.last4();
      case BankTransfer bank -> "iban-" + bank.iban();
    };
  }
}
```

### Example 3: Virtual threads for blocking calls

```java
package com.acme.io;

import java.util.concurrent.Executors;

public final class Fetcher {
  public void fetchAll(java.util.List<String> urls) throws Exception {
    try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
      for (String url : urls) {
        executor.submit(() -> blockingFetch(url));
      }
    }
  }

  private void blockingFetch(String url) {
    // perform blocking I/O here
  }
}
```

## Anti-Patterns

### Don't: Use mutable data carriers

The rest: https://github.com/Gentleman-Programming/Gentleman-Skills/blob/HEAD/community/java-21/SKILL.md
