java-expert
java-expert
Keyword: java | Platforms: gemini,claude,codex
High-Performance Modern Java Expert Skill - Specialized in Java 21+ and cloud-native architecture.
Core Mandates
- Google Java Style: Strictly adhere to the Google Java Style Guide for formatting, naming, and structure.
- Java 21+ First: Mandate
var(LVTI) where readable, Records for DTOs, and Pattern Matching forinstanceofandswitch. - Concurrency: Prefer Virtual Threads (
@RunOnVirtualThreadin Quarkus orExecutors.newVirtualThreadPerTaskExecutor()) over traditional Thread Pools for I/O-bound tasks. - Immutability: Use
record,finalfields, andunmodifiablecollections (List.of,Map.of). - Functional Style: Leverage Streams,
Optional, and Functional Interfaces to reduce boilerplate and side effects. - Visibility: Default to
package-privateorprivate. Onlypublicwhat must be exposed (API/SPI).
Virtual Threads (Project Loom)
When to Use Virtual Threads
Is the task I/O-bound (DB queries, HTTP calls, file reads)?
YES → Virtual Threads (scales to millions of concurrent tasks)
NO → Is it CPU-bound (crypto, compression, ML inference)?
YES → Platform Threads with ForkJoinPool (work-stealing)
NO → Is it reactive streaming with backpressure?
YES → Mutiny / Vert.x (Reactive Streams)
NO → Virtual Threads (default choice for most workloads)
Patterns
// PATTERN 1: Simple virtual thread executor
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
List<Future<String>> futures = urls.stream()
.map(url -> executor.submit(() -> fetchUrl(url)))
.toList();
List<String> results = futures.stream()
.map(f -> { try { return f.get(); } catch (Exception e) { throw new RuntimeException(e); } })
.toList();
}
// PATTERN 2: Structured Concurrency (Preview in 21, stable in 25)
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
var userTask = scope.fork(() -> userService.findById(id));
var orderTask = scope.fork(() -> orderService.findByUser(id));
scope.join().throwIfFailed();
return new UserProfile(userTask.get(), orderTask.get());
}
// PATTERN 3: Quarkus integration
@Path("/users")
public class UserResource {
@GET
@RunOnVirtualThread // Offloads blocking call to virtual thread
public List<User> list() {
return User.listAll(); // Blocking Panache call - safe on VT
}
}
Anti-Patterns
// BAD - synchronized blocks pin virtual threads to carrier threads
synchronized (lock) {
var result = db.query("SELECT ..."); // Pins carrier thread!
}
// GOOD - use ReentrantLock instead (does not pin)
lock.lock();
try {
var result = db.query("SELECT ...");
} finally {
lock.unlock();
}
// BAD - ThreadLocal with large state on virtual threads (millions of VTs = millions of copies)
private static final ThreadLocal<ExpensiveCache> cache = ThreadLocal.withInitial(ExpensiveCache::new);
// GOOD - use ScopedValue (Preview) or shared concurrent structure
private static final ScopedValue<RequestContext> CONTEXT = ScopedValue.newInstance();
void handleIncoming(RequestContext ctx) {
ScopedValue.runWhere(CONTEXT, ctx, () -> handleRequest());
}
// BAD - pooling virtual threads (defeats the purpose)
ExecutorService pool = Executors.newFixedThreadPool(100); // Platform threads only!
// GOOD - create virtual threads freely, they are cheap
ExecutorService vt = Executors.newVirtualThreadPerTaskExecutor();
Records
// PATTERN: Record as immutable DTO with validation
public record CreateUserRequest(
@NotBlank String name,
@Email String email,
@Min(18) int age
) {
// Compact constructor for validation
public CreateUserRequest {
name = name.strip();
email = email.toLowerCase();
}
}
// PATTERN: Record with derived fields
public record Money(BigDecimal amount, Currency currency) {
public Money add(Money other) {
if (!currency.equals(other.currency)) throw new IllegalArgumentException("Currency mismatch");
return new Money(amount.add(other.amount), currency);
}
}
// ANTI-PATTERN: Don't use records for mutable entities
// BAD - records are immutable, JPA entities need mutability
@Entity
public record User(Long id, String name) {} // Won't work with Hibernate
// GOOD - use class for JPA entities
@Entity
public class User {
@Id @GeneratedValue private Long id;
private String name;
}
Pattern Matching
instanceof Pattern Matching
// BAD - old style with explicit cast
if (shape instanceof Circle) {
Circle c = (Circle) shape;
return Math.PI * c.radius() * c.radius();
}
// GOOD - pattern variable binding
if (shape instanceof Circle c) {
return Math.PI * c.radius() * c.radius();
}
// GOOD - guarded patterns
if (shape instanceof Circle c && c.radius() > 0) {
return Math.PI * c.radius() * c.radius();
}
Switch Pattern Matching (Java 21 - finalized)
// Exhaustive switch with sealed types
sealed interface Shape permits Circle, Rectangle, Triangle {}
record Circle(double radius) implements Shape {}
record Rectangle(double w, double h) implements Shape {}
record Triangle(double base, double height) implements Shape {}
double area(Shape shape) {
return switch (shape) {
case Circle c -> Math.PI * c.radius() * c.radius();
case Rectangle r -> r.w() * r.h();
case Triangle t -> 0.5 * t.base() * t.height();
// No default needed - compiler ensures exhaustiveness
};
}
// Guarded patterns with when
String classify(Object obj) {
return switch (obj) {
case Integer i when i < 0 -> "negative";
case Integer i when i == 0 -> "zero";
case Integer i -> "positive";
case String s when s.isBlank() -> "blank string";
case String s -> "string: " + s;
case null -> "null";
default -> "unknown: " + obj.getClass();
};
}
Sealed Classes
// PATTERN: Domain modeling with sealed hierarchy
public sealed interface PaymentMethod permits CreditCard, BankTransfer, Wallet {
BigDecimal maxAmount();
}
public record CreditCard(String number, YearMonth expiry) implements PaymentMethod {
public BigDecimal maxAmount() { return new BigDecimal("10000"); }
}
public record BankTransfer(String iban) implements PaymentMethod {
public BigDecimal maxAmount() { return new BigDecimal("1000000"); }
}
public record Wallet(String walletId, BigDecimal balance) implements PaymentMethod {
public BigDecimal maxAmount() { return balance; }
}
// Compiler enforces exhaustiveness - adding a new PaymentMethod
// will cause compile errors wherever a switch doesn't cover it
String processPayment(PaymentMethod method, BigDecimal amount) {
return switch (method) {
case CreditCard cc -> chargeCard(cc, amount);
case BankTransfer bt -> initTransfer(bt, amount);
case Wallet w -> debitWallet(w, amount);
};
}
Migration Guide: Java 11/17 → 21
Key Changes by Version
| Feature | Java 11 | Java 17 | Java 21 |
|---|---|---|---|
| Text blocks | ❌ | ✅ """...""" |
✅ |
| Records | ❌ | ✅ | ✅ |
| Sealed classes | ❌ | ✅ (final) | ✅ |
| Pattern matching instanceof | ❌ | ✅ (final) | ✅ |
| Switch pattern matching | ❌ | ❌ (preview) | ✅ (final) |
| Virtual Threads | ❌ | ❌ | ✅ (final) |
| Sequenced Collections | ❌ | ❌ | ✅ |
| String templates | ❌ | ❌ | Preview |
Common Migration Patterns
// Java 11 → 21: Replace verbose instanceof chains
// BEFORE (Java 11)
if (event instanceof OrderCreated) {
OrderCreated e = (OrderCreated) event;
handle(e);
} else if (event instanceof OrderCancelled) {
OrderCancelled e = (OrderCancelled) event;
cancel(e);
}
// AFTER (Java 21)
switch (event) {
case OrderCreated e -> handle(e);
case OrderCancelled e -> cancel(e);
default -> log.warn("Unknown event: {}", event);
}
// Java 11 → 21: Replace DTOs with Records
// BEFORE
public class UserDto {
private final String name;
private final String email;
public UserDto(String name, String email) { this.name = name; this.email = email; }
public String getName() { return name; }
public String getEmail() { return email; }
// equals, hashCode, toString...
}
// AFTER
public record UserDto(String name, String email) {}
// Java 11 → 21: Replace Thread pools for I/O tasks
// BEFORE
ExecutorService pool = Executors.newFixedThreadPool(200);
Future<String> f = pool.submit(() -> httpClient.send(req).body());
// AFTER
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
Future<String> f = executor.submit(() -> httpClient.send(req).body());
}
Migration Gotchas
finalize()removed → useCleaneror try-with-resources- Security Manager removed → migrate to other security mechanisms
- Nashorn removed (Java 15) → use GraalVM polyglot for JS
- Applet API removed → N/A for server-side
Thread.stop()throws UOE → use interruption pattern withThread.interrupt()
Architectural Patterns
Hexagonal / Clean Architecture
- Domain: Pure Java, zero external dependencies (no Quarkus/Spring in domain classes).
- Ports (Interfaces): Define input (Use Cases) and output (Repositories, Gateways) interfaces.
- Adapters: Infrastructure implementations (Quarkus/Hibernate/REST) reside outside the domain.
Performance & Memory
- Garbage Collection: Favor G1GC for typical workloads or ZGC for ultra-low latency (<1ms).
- Memory Management: Minimize object allocation in hot loops. Use
StringBuilderinstead of+in loops. - Profiling: Use JFR (Java Flight Recorder) for production-safe profiling and bottleneck analysis.
GC Decision Tree
Workload type?
General server (most cases) → G1GC (-XX:+UseG1GC, default in JDK 21)
Ultra-low latency (<1ms pause) → ZGC (-XX:+UseZGC)
Small heap (<256MB), short-lived → SerialGC (-XX:+UseSerialGC)
Native Image (GraalVM) → SerialGC (default) or G1 (--gc=G1)
High throughput batch → G1GC with large heap + tuned regions
Testing Strategy
- JUnit 5 & AssertJ: The industry standard for fluent, readable assertions.
- Mockito: Deep stubbing and spying for complex dependencies.
- ArchUnit: Enforce architectural rules (e.g., "Domain must not depend on Infrastructure").
- Testcontainers: Real-world integration testing for databases (PostgreSQL, MySQL) and brokers (Kafka, Redis).
Bytecode & Classloading
- Jandex: Understand Jandex indexing for Quarkus's fast annotation scanning.
- Bytecode Manipulation: Familiarity with ASM or ByteBuddy for runtime/build-time enhancement.
- ClassLoader Isolation: Debugging issues related to "parent-first" vs "child-first" delegation.
Expert Tips
- Avoid
System.out.println(); always use a logger (SLF4J/Logback). - Prefer
Interface-baseddesign for testability. - Use
Sealed Classesto define closed hierarchy types for better exhaustiveness checking inswitch. - Use
List.copyOf()/Map.copyOf()to defensively copy mutable collections in public APIs. - Prefer
Optional.orElseThrow()overOptional.get()(never call.get()without.isPresent()).
🌐 Java Knowledge Sources
Directive: Use
web_fetchto find the latest JDK 21+ features, JEP details, or performance tuning flags (G1GC, ZGC) before giving architecture advice.
- JDK 21 Release Notes: Java 21 Documentation - Breaking changes and new APIs.
- Coding Standards: Google Java Style Guide - Formatting, naming, and whitespace conventions.
- Virtual Threads (Project Loom): JEP 444 - Comprehensive guide to Virtual Threads.
- Modern Concurrency: Structured Concurrency (JEP 453) - Managing subtasks.
- Performance Tuning: HotSpot Virtual Machine Garbage Collection - Tuning G1 and ZGC.
References
- Official Java SE Documentation
- Google Java Style Guide
- Effective Java (Joshua Bloch)
- Java Flight Recorder (JFR) Reference
- JUnit 5 User Guide
Skill Interoperability
The java-expert ☕ skill provides the foundational language expertise (JDK 21+, Virtual Threads) required by:
- vertx-expert 🌀: Uses modern Java for high-performance reactive programming.
- quarkus-expert ⚡: Leverages the JVM features for the Quarkus framework.
More from kinhluan/rules-quarkus-skills
quarkus-expert
High-performance Quarkus framework expertise covering reactive patterns, CDI, build-time augmentation, and cloud-native development. Use for general Quarkus questions.
19gradle-expert
Expert knowledge for Gradle Build Tool, dependency management, and Gradle-to-Bazel migration. Use for build configuration and project lifecycle questions.
15vertx-expert
Expert knowledge for Eclipse Vert.x, the reactive engine behind Quarkus. Use for deep reactive programming, Event Loop, and non-blocking I/O questions.
13bazel-expert
Expert knowledge for writing idiomatic Bazel rules, Starlark best practices, and build performance optimization. Use for Bazel build system questions.
9maven-expert
Expert knowledge for Apache Maven, dependency management, BOMs, and Maven-to-Bazel migration. Use for build configuration and project lifecycle questions.
9rules-quarkus
Expert knowledge for building Quarkus applications with Bazel using the rules_quarkus build system. Use when user asks about Quarkus+Bazel builds, augmentation, or troubleshooting.
8