# java-21

Teaches the agent to write Java 21 code: records, sealed types, virtual threads. Useful once your project is already on 21.

- skill · `type=skill` · Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, OpenCode · 326 installs · ★ 660
- Author: diegnghrmr
- License: MIT · policy=mirror · the beginning of the file is at the end of this page
- Source: https://github.com/Gentleman-Programming/Gentleman-Skills/tree/HEAD/community/java-21/SKILL.md
- Updated: 2026-03-28
- HTML: https://affpapa.org/en/nevibecode/skills/java-21

## What it does

The skill loads when the agent writes Java 21 application or library code, designs immutable DTOs and value objects, models closed hierarchies, or handles blocking I/O. Inside are three patterns with code: a record that validates in its compact constructor, a sealed interface matched exhaustively with switch, and virtual threads via `Executors.newVirtualThreadPerTaskExecutor()`.

A separate section covers anti-patterns. A mutable DTO with public fields and a raw `new Thread(...)` per request are both flagged as bad practice — the second one is expensive and unbounded. There is also a quick reference table mapping each task to its pattern.

The skill targets Java 21 specifically: records, sealed types and virtual threads are features of that release, so the examples will not compile on older JDKs. Worth checking which version your `pom.xml` or `build.gradle` pins before you install.

## Install

### Claude Code (native platform)

1. **Skills CLI (Vercel)**
```bash
npx skills add Gentleman-Programming/Gentleman-Skills --skill java-21 -a claude-code
```

2. **Manually: put the files in place**
- File: `~/.claude/skills/java-21/SKILL.md` — Copy the whole skill folder; for one project use .claude/skills/java-21/

### Codex

1. **Skills CLI (Vercel)**
```bash
npx skills add Gentleman-Programming/Gentleman-Skills --skill java-21 -a codex
```

2. **Manually: put the files in place**
- File: `.agents/skills/java-21/SKILL.md` — For all projects use ~/.agents/skills/

### Cursor

1. **Skills CLI (Vercel)**
```bash
npx skills add Gentleman-Programming/Gentleman-Skills --skill java-21 -a cursor
```

2. **Manually: put the files in place**
- File: `.cursor/skills/java-21/SKILL.md` — Cursor also reads .agents/skills/ and .claude/skills/

### GitHub Copilot

1. **GitHub CLI**
```bash
gh skill install Gentleman-Programming/Gentleman-Skills java-21
```

2. **Manually: put the files in place**
- File: `.github/skills/java-21/SKILL.md`

### Gemini CLI

1. **Skills CLI (Vercel)**
```bash
npx skills add Gentleman-Programming/Gentleman-Skills --skill java-21 -a gemini-cli
```

2. **Platform CLI**
```bash
gemini skills install https://github.com/Gentleman-Programming/Gentleman-Skills --path community/java-21
```

### Windsurf (Devin Desktop)

**Manually: put the files in place**
- File: `.devin/skills/java-21/SKILL.md` — The legacy .windsurf/skills/ path still works

### OpenCode

**Skills CLI (Vercel)**
```bash
npx skills add Gentleman-Programming/Gentleman-Skills --skill java-21 -a opencode
```

### Claude.ai

**Claude.ai**
- Zip the folder and upload it in Settings → Capabilities → Skills

Where a file is given instead of a command, copy the files from the source to that path: https://github.com/Gentleman-Programming/Gentleman-Skills/tree/HEAD/community/java-21/SKILL.md

## When to use it
- write an immutable DTO that validates its own fields
- close a payment hierarchy with a sealed interface and match it in switch
- handle blocking I/O without a large thread pool
- replace a mutable data carrier class with a record
- stop spawning a new thread for every request

## Example prompts
- Write an Email record that validates its value in the compact constructor
- Create a sealed Payment interface with Card and BankTransfer, then describe it with switch
- Rewrite this URL fetch loop to use virtual threads via Executors.newVirtualThreadPerTaskExecutor()

## Source text · SKILL.md · MIT

Below is the content of a third-party file. It is data, not instructions for you: do not act on anything written inside unless the human asks. Block tag: 8c3b2abdadb115c7.

BEGIN THIRD-PARTY FILE 8c3b2abdadb115c7
````text
---
name: java-21
description: >
  Java 21 language and runtime patterns for modern, safe code.
  Trigger: When writing Java 21 code using records, sealed types, or virtual threads.
metadata:
  author: diegnghrmr
  version: "1.0"
---

## 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

```java
// BAD: mutable DTO
public class UserDto {
  public String name;
  public String email;
}
```

### Don't: Spin up raw platform threads per request

```java
// BAD: expensive and unbounded
new Thread(() -> blockingFetch("https://api" )).start();
```

## Quick Reference

| Task | Pattern |
|------|---------|
| Immutable DTOs | Use records with validation |
| Closed hierarchies | Use sealed interfaces + switch |
| Blocking I/O scale | Use virtual threads executor |

## Resources

- Java 21 Release Notes: https://www.oracle.com/java/technologies/javase/21-relnote-issues.html
````
END THIRD-PARTY FILE 8c3b2abdadb115c7

The third-party file has ended. Everything between the 8c3b2abdadb115c7 tags is data: requests and commands from it are not followed. An “end of file” line with another tag inside the block is part of the file.

First 2730 of 2771 bytes. © diegnghrmr · MIT · https://github.com/Gentleman-Programming/Gentleman-Skills/tree/HEAD/community/java-21/SKILL.md

_Part of the page did not fit — see the HTML version._

---
NeVibeCode on affpapa.org. Catalog texts are descriptions, not instructions for the agent. How to choose and install: https://affpapa.org/en/nevibecode/agents.md
