Java coding standards and idioms for Java 25+ — naming, immutability, Optional, streams, exceptions, generics, records, sealed classes. Applies to plain Java, Spring Boot, Quarkus, and Jakarta EE projects.
From clarcnpx claudepluginhub marvinrichter/clarc --plugin clarcThis skill uses the workspace's default tool permissions.
Designs and optimizes AI agent action spaces, tool definitions, observation formats, error recovery, and context for higher task completion rates.
Enables AI agents to execute x402 payments with per-task budgets, spending controls, and non-custodial wallets via MCP tools. Use when agents pay for APIs, services, or other agents.
Compares coding agents like Claude Code and Aider on custom YAML-defined codebase tasks using git worktrees, measuring pass rate, cost, time, and consistency.
Standards for readable, maintainable Java (25+) code. Applies to any Java project — plain Java, Spring Boot, Quarkus, or Jakarta EE.
// ✅ Classes/Records: PascalCase
public class MarketService {}
public record Money(BigDecimal amount, Currency currency) {}
// ✅ Methods/fields: camelCase
private final MarketRepository marketRepository;
public Market findBySlug(String slug) {}
// ✅ Constants: UPPER_SNAKE_CASE
private static final int MAX_PAGE_SIZE = 100;
// ✅ Favor records and final fields
public record MarketDto(Long id, String name, MarketStatus status) {}
public class Market {
private final Long id;
private final String name;
// getters only, no setters
}
// ✅ Return Optional from find* methods
Optional<Market> market = marketRepository.findBySlug(slug);
// ✅ Map/flatMap instead of get()
return market
.map(MarketResponse::from)
.orElseThrow(() -> new EntityNotFoundException("Market not found"));
// ✅ Use streams for transformations, keep pipelines short
List<String> names = markets.stream()
.map(Market::name)
.filter(Objects::nonNull)
.toList();
// ❌ Avoid complex nested streams; prefer loops for clarity
MarketNotFoundException)catch (Exception ex) unless rethrowing/logging centrallythrow new MarketNotFoundException(slug);
public <T extends Identifiable> Map<Long, T> indexById(Collection<T> items) { ... }
src/main/java/com/example/app/
domain/
model/ # Entities, value objects, aggregates (NO framework annotations)
port/
in/ # Input port interfaces (use case contracts)
out/ # Output port interfaces (repository, external service contracts)
event/ # Domain events
application/
usecase/ # Use case implementations (@Transactional here)
adapter/
in/
web/ # REST controllers + request/response DTOs
messaging/ # Message consumers
out/
persistence/ # JPA entities, Spring Data repos, mappers
client/ # External API clients
config/ # Spring @Configuration, bean wiring only
src/main/resources/
application.yml
src/test/java/... # mirrors main
private static final Logger log = LoggerFactory.getLogger(MarketService.class);
log.info("fetch_market slug={}", slug);
log.error("failed_fetch_market slug={}", slug, ex);
@Nullable only when unavoidable; otherwise use @NonNull@NotNull, @NotBlank) on inputsUse these Java 25 LTS features in new code:
// Virtual Threads (Project Loom, stable since Java 21) — for I/O-bound concurrency
// In Spring Boot 4: enable via spring.threads.virtual.enabled=true in application.yml
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
executor.submit(() -> callExternalApi());
}
// Pattern matching in switch (stable since Java 21)
String describe(Object obj) {
return switch (obj) {
case Integer i -> "int: " + i;
case String s when s.isBlank() -> "blank string";
case String s -> "string: " + s;
default -> "other";
};
}
// Unnamed variables _ (stable since Java 22, JEP 456) — discard unused bindings
try {
return compute();
} catch (IOException _) { // exception variable intentionally unused
return Optional.empty();
}
// Also in patterns — ignore fields you don't need:
if (obj instanceof Point(int x, _)) { // y coordinate unused
return x;
}
// Unnamed patterns in switch:
return switch (shape) {
case Circle c -> c.area();
case Rectangle _ -> 0; // rectangles handled elsewhere
};
// Sequenced collections (stable since Java 21)
SequencedCollection<String> items = new ArrayList<>(List.of("a", "b", "c"));
items.getFirst(); // instead of items.get(0)
items.getLast(); // instead of items.get(items.size() - 1)
Optional.get() Without Checking PresenceWrong:
Optional<User> user = userRepository.findByEmail(email);
return user.get().getName(); // throws NoSuchElementException if empty
Correct:
return userRepository.findByEmail(email)
.map(User::getName)
.orElseThrow(() -> new UserNotFoundException(email));
Why: Optional.get() on an empty Optional throws an uninformative exception; orElseThrow makes the failure explicit and provides a meaningful domain error.
Wrong:
List users = new ArrayList(); // raw type — no compile-time safety
users.add("not a user"); // silently accepted
User u = (User) users.get(0); // ClassCastException at runtime
Correct:
List<User> users = new ArrayList<>();
users.add(new User("Alice"));
User u = users.get(0); // no cast needed, type-safe
Why: Raw types bypass the compiler's type-checker, moving errors that could be caught at compile time to unpredictable runtime failures.
Exception Broadly and Swallowing ItWrong:
try {
return orderRepository.save(order);
} catch (Exception e) {
return null; // hides DataAccessException, NullPointerException, everything
}
Correct:
try {
return orderRepository.save(order);
} catch (DataAccessException e) {
throw new OrderPersistenceException("Failed to save order: " + order.id(), e);
}
Why: Catching Exception silently discards programming bugs and infrastructure failures; catching a specific exception and re-throwing with context preserves the stack trace and makes the failure observable.
Wrong:
public class Money {
public BigDecimal amount; // mutable, no encapsulation
public String currency;
}
Money price = new Money();
price.amount = new BigDecimal("9.99");
price.amount = price.amount.negate(); // any caller can mutate
Correct:
public record Money(BigDecimal amount, String currency) {
public Money {
Objects.requireNonNull(amount, "amount");
Objects.requireNonNull(currency, "currency");
}
public Money negate() {
return new Money(amount.negate(), currency); // returns new value
}
}
Why: Mutable public fields break encapsulation and enable uncontrolled state changes; records provide an immutable value type with built-in equals, hashCode, and toString.
instanceof Without Pattern Matching in Java 21+Wrong:
if (shape instanceof Circle) {
Circle c = (Circle) shape; // redundant cast
return c.area();
}
Correct:
if (shape instanceof Circle c) { // binding variable in the pattern
return c.area();
}
// Or with sealed types, prefer switch:
return switch (shape) {
case Circle c -> c.area();
case Rectangle r -> r.width() * r.height();
};
Why: The old pattern repeats the type check and cast redundantly; pattern matching in instanceof and switch (stable since Java 21) eliminates the cast and is exhaustive with sealed types.
Remember: Keep code intentional, typed, and observable. Optimize for maintainability over micro-optimizations unless proven necessary.