From java-skills
Use when writing, reviewing, or modifying Java/JVM source — the house standard for everyday Java craft: design and naming (composition over inheritance, interfaces over implementations, enums, Optional-as-return, no raw types), structure and immutability, dependency injection, exception handling, resource management, input validation, strings, date/time, comments, and gating features to the project's JDK version. Covers almost any Java change that isn't specifically tests or observability.
How this skill is triggered — by the user, by Claude, or both
Slash command
/java-skills:java-developmentThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
The house standard for writing Java well. Apply these as a set on any Java change. For tests use the
The house standard for writing Java well. Apply these as a set on any Java change. For tests use the
java-testing skill; for logging/metrics/tracing use the java-observability skill.
First, know your JDK. Only use language/library features that are final in the project's
configured Java version; never use preview/incubator features unless the project already enables
--enable-preview. Detect the version and read the matching catalog in references/version/ — see
Version gating.
final unless mutation is intentional and justified.if/for/while/else, even single-line bodies.public final class InvoiceService {
private final InvoiceRepository repository;
public InvoiceService(final InvoiceRepository repository) {
this.repository = Objects.requireNonNull(repository, "repository");
}
public BigDecimal total(final Invoice invoice) {
if (invoice.lineItems().isEmpty()) {
return BigDecimal.ZERO;
}
final BigDecimal subtotal = invoice.lineItems().stream()
.map(LineItem::amount).reduce(BigDecimal.ZERO, BigDecimal::add);
return subtotal;
}
}
calculateTotalPrice, timeoutInMilliseconds), no abbreviations.ifs.final unless explicitly designed for extension.List/Map/Set, not ArrayList/HashMap. Prefer
collections over arrays.@Override; enums over int/String constants.Optional is a return type only — never a field, parameter, or collection element.equals and hashCode together, never one alone — or use a record.// ❌ nested conditionals, int constants, silent fall-through
if (order != null) {
if (!order.items().isEmpty()) {
if (type == STANDARD) { fee = base; } else if (type == EXPRESS) { fee = base * 2; }
}
}
// ✅ guard clauses + enum + exhaustive switch expression (14+)
Objects.requireNonNull(order, "order");
if (order.items().isEmpty()) {
return BigDecimal.ZERO;
}
return switch (order.type()) { // compiler enforces every ShippingType is handled
case STANDARD -> baseFee;
case EXPRESS -> baseFee.multiply(EXPRESS_MULTIPLIER);
};
Validate untrusted input at the boundary, immediately — fail fast by throwing a clear,
specific exception (no secrets/PII in messages). Never return a default/sentinel (0, null,
empty) for invalid input — that hides the bug. Objects.requireNonNull(x, "x") for nulls; blank
checks (x == null || x.isBlank(), or StringUtils.isBlank) for strings. Never let invalid data
flow deeper.
catch (Exception) for true top-level boundaries.throw new XException("context", e).InterruptedException, restore the flag: Thread.currentThread().interrupt() then propagate.finally/cleanup mask the original failure. Exceptions are not control flow.Always try-with-resources, never try/finally. Watch the easy-to-miss ones: Files.lines(...)
and Files.newDirectoryStream(...) return a resource that must be closed.
try (final Stream<String> lines = Files.lines(path)) {
return lines.filter(l -> !l.isBlank()).toList();
}
.formatted(...) / String.format(...) for interpolation — not +.String.join(delim, ...) for joining known elements.StringBuilder/StringJoiner in loops; never + in a loop.Instant preferred). Inject a java.time.Clock for "now"
(clock.instant()) — never Instant.now()/LocalDateTime.now() directly (untestable).LocalDateTime (no offset). Be explicit about ZoneId; default to ISO-8601.Comment intent, not mechanics — don't restate the signature. Javadoc public APIs: behavior,
@throws conditions, edge cases/invariants. Avoid redundant/stale comments. Markdown Javadoc
(///, JEP 467) only on Java 23+ — don't convert existing standard Javadoc.
Detect the project's Java version, then read the matching cumulative catalog (each includes earlier
LTS releases): references/version/java-8.md, java-11.md, java-17.md, java-21.md, java-25.md.
| Build tool | Where to look |
|---|---|
| Maven | maven-compiler-plugin <release>/<source>, or maven.compiler.release / java.version |
| Gradle | java.toolchain.languageVersion, or sourceCompatibility/targetCompatibility |
If undeterminable: the lowest LTS the project mentions, else Java 8 (Maven's default baseline). Don't assume the JDK you happen to be running. Preview features have been removed before (string templates, gone in 23) — never depend on them.
final; a control statement without braces; field/setter injection@Override; an Optional field/parameter; equals without hashCodeArrayList not List+ interpolation or + in a loop; Instant.now()/LocalDateTime; Files.lines(...) not in try (...)catch (Exception) outside a boundary; swallowed exception or lost cause; swallowed InterruptedExceptionProvides behavioral guidelines to reduce common LLM coding mistakes, focusing on simplicity, surgical changes, assumption surfacing, and verifiable success criteria.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub mtkhawaja/java-skills --plugin java-skills