Skip to main content

java

Use this skill when the user says 'java', 'maven', 'gradle', 'records', 'sealed classes', 'virtual threads', 'streams', 'Optional', 'JUnit', 'JVM tuning'. Covers modern Java (17/21/25 LTS) language features, build tooling, concurrency, testing and JVM production settings. Do NOT use for: Spring Boot application architecture (use backend/spring-boot), Kotlin (use lang-kotlin), Android (use android).

Source facts

Repository
j4flmao/agent-skills
Last source activity
October 28, 2026 at 00:50
Detected SKILL.md language
English
Stars
39
Forks
5

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
10 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
java
description
Use this skill when the user says 'java', 'maven', 'gradle', 'records', 'sealed classes', 'virtual threads', 'streams', 'Optional', 'JUnit', 'JVM tuning'. Covers modern Java (17/21/25 LTS) language features, build tooling, concurrency, testing and JVM production settings. Do NOT use for: Spring Boot application architecture (use backend/spring-boot), Kotlin (use lang-kotlin), Android (use android).
version
1.0.0
author
j4flmao
license
MIT
compatibility
{"claude-code":true,"cursor":true,"codex":true,"windsurf":true}
tags
["java","language","build","jvm"]
# Java ## Purpose Guide for Java build tools (Maven/Gradle), module system, modern language features (records, sealed classes, pattern matching), streams, concurrency, testing, and production deployment. ## Agent Protocol ### Trigger Keywords: `java build`, `maven`, `gradle`, `java module`, `record`, `stream`, `optional`, `completablefuture`, `junit`, `spring boot`, `jakarta`. ### Input Context - Build tool (Maven, Gradle) - Java version - Framework (Spring Boot, Quarkus, Micronaut, Jakarta EE) - Deployment target ### Output Artifact Code, build-file changes, or JVM flags. No file unless requested. ### Response Format ``` Java: {release} Build: {maven|gradle} Change: {what and why} Code: {snippet} Verify: {mvn verify | ./gradlew check} ``` ## Decision Trees ### Build Tool Selection ``` Team preference? ├── Declarative, XML, convention → Maven (stable, predictable, standard) │ ├── pom.xml, lifecycle phases (compile, test, package) │ └── Best for: large orgs, strict conventions, established projects ├── Flexible, programmable, fast → Gradle (Kotlin DSL, incremental builds) │ ├── build.gradle.kts, task-based, build cache │ └── Best for: Android, multi-module, custom build logic └── Modern, fast, no-nonsense → Maven + mvnd (Maven Daemon, parallel builds) ``` ### Framework Selection ``` What kind of application? ├── Full-stack web app → Spring Boot (most mature, vast ecosystem, auto-config) ├── Cloud-native / low-resource → Quarkus (GraalVM native, fast startup) ├── Microservices / reactive → Micronaut (compile-time DI, AOT) ├── REST API / lightweight → JAX-RS (Jakarta REST) + Helidon / Dropwizard └── Batch processing → Spring Batch / Apache Beam ``` ### Module Strategy ``` Project size? ├── Small (<10k LOC) → Single module, package-based organization ├── Medium (10-100k LOC) → Multi-module with clear boundaries (api, core, infra) ├── Large (>100k LOC) → Java Platform Module System (JPMS) with module-info.java └── Library → Single module, minimize exports, use JPMS for strong encapsulation ``` ## Build & Dependency Management ### Maven pom.xml ```xml <project> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.3.0</version> </parent> <properties> <java.version>21</java.version> <maven.compiler.source>21</maven.compiler.source> <maven.compiler.target>21</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> </project> ``` ### Gradle build.gradle.kts ```kotlin plugins { java id("org.springframework.boot") version "3.3.0" id("io.spring.dependency-management") version "1.1.5" } java { toolchain { languageVersion = JavaLanguageVersion.of(21) } } dependencies { implementation("org.springframework.boot:spring-boot-starter-web") testImplementation("org.springframework.boot:spring-boot-starter-test") compileOnly("org.projectlombok:lombok") annotationProcessor("org.projectlombok:lombok") } ``` ### Version Catalog (Gradle) ```toml # gradle/libs.versions.toml [versions] spring-boot = "3.3.0" testcontainers = "1.19.0" [libraries] spring-boot-starter = { module = "org.springframework.boot:spring-boot-starter-web", version.ref = "spring-boot" } testcontainers = { module = "org.testcontainers:testcontainers", version.ref = "testcontainers" } ``` ## Language-Specific Patterns ### Records (Java 16+) ```java // Immutable data carrier — replaces Lombok @Data, manual POJOs public record Order(Long id, String customer, BigDecimal total, OrderStatus status) { // Compact constructor for validation public Order { if (total.compareTo(BigDecimal.ZERO) < 0) { throw new IllegalArgumentException("total must be positive"); } if (status == null) status = OrderStatus.PENDING; } // Static factory public static Order create(String customer, BigDecimal total) { return new Order(null, customer, total, OrderStatus.PENDING); } } ``` ### Sealed Classes (Java 17+) ```java // Exhaustive hierarchy — compiler knows all subtypes public sealed interface Payment permits CreditCard, PayPal, CryptoPayment {} public record CreditCard(String lastFour, String expiry) implements Payment {} public record PayPal(String email) implements Payment {} public record CryptoPayment(String walletAddress, String currency) implements Payment {} // Switch with pattern matching (Java 21+) public String processPayment(Payment payment) { return switch (payment) { case CreditCard c -> "Processing card ending in " + c.lastFour(); case PayPal p -> "Redirecting to PayPal for " + p.email(); case CryptoPayment cp -> "Verifying " + cp.currency() + " transfer"; }; } ``` ### Streams & Optional ```java // Stream pipeline List<String> activeCustomerEmails = orders.stream() .filter(Order::isPaid) .map(Order::customer) .distinct() .sorted() .toList(); // Java 16+ — no need for .collect(Collectors.toList()) // Optional usage public Customer findCustomer(Long id) { return repository.findById(id) .orElseThrow(() -> new CustomerNotFoundException(id)); } // Optional chaining String city = customer .flatMap(Customer::getAddress) .map(Address::getCity) .orElse("Unknown"); ``` ### CompletableFuture ```java public CompletableFuture<OrderResult> processOrderAsync(OrderRequest request) { return CompletableFuture .supplyAsync(() -> validateOrder(request), executor) .thenCompose(validated -> CompletableFuture.supplyAsync(() -> saveOrder(validated), executor)) .thenApplyAsync(this::enrichResult, executor) .exceptionally(throwable -> { log.error("Order processing failed", throwable); return OrderResult.failed(throwable.getMessage()); }); } // Combine multiple async results CompletableFuture<Void> all = CompletableFuture.allOf(f1, f2, f3); all.thenRun(() -> { /* all complete */ }); ``` ## Testing & Tooling ### JUnit 5 ```java import org.junit.jupiter.api.*; class OrderServiceTest { @Test void createOrder_setsPendingStatus() { var order = service.createOrder(customerId, items); assertEquals(OrderStatus.PENDING, order.status()); } @ParameterizedTest @CsvSource({ "1, 10.0", "2, 20.0", "5, 50.0" }) void calculateTotal_multipliesQuantity(int qty, double expected) { assertEquals(BigDecimal.valueOf(expected), service.calculateTotal(item, qty)); } @TestFactory Stream<DynamicTest> dynamicTests() { return testCases.stream() .map(tc -> DynamicTest.dynamicTest(tc.name(), () -> { assertEquals(tc.expected(), service.process(tc.input())); })); } } ``` ### Spring Boot Test ```java @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) @AutoConfigureMockMvc class OrderControllerTest { @Autowired private MockMvc mockMvc; @Test void createOrder_returns201() throws Exception { mockMvc.perform(post("/api/orders") .contentType(MediaType.APPLICATION_JSON) .content(""" {"customerId": 1, "items": [{"productId": 1, "qty": 2}]} """)) .andExpect(status().isCreated()) .andExpect(jsonPath("$.id").isNumber()); } } ``` ### Tooling ```bash # Build and test ./mvnw clean verify # Maven wrapper (no local install needed) ./gradlew build # Gradle wrapper # JVM tuning java -Xms512m -Xmx2g -XX:+UseZGC -jar app.jar # ZGC for low-latency GC # Profiling jcmd <pid> VM.native_memory # Native memory tracking jmap -dump:live,format=b <pid> # Heap dump jstack <pid> # Thread dump async-profiler -e cpu -d 30 -f profile.jfr ``` ## Anti-Patterns - **Raw `null` returns**: Forces callers to null-check. Use `Optional` for possibly-empty returns - **Checked exceptions overused**: Callers forced to catch or declare. Use unchecked exceptions for non-recoverable - **`synchronized` on hot methods**: Contention kills throughput. Use `ReentrantLock`, `StampedLock`, or `ConcurrentHashMap` - **God class with 5000+ lines**: Impossible to test, modify, or understand. Split by responsibility - **`System.out.println` in production code**: Use SLF4J + Logback/Log4j2 with proper levels - **`new Date()` / `System.currentTimeMillis()` in tight loops**: Creates objects. Cache or use `Instant.now()` - **Double-checked locking without `volatile`**: Broken without volatile on the field. Use `Thread-safe` holder pattern - **`Vector`, `Hashtable`, `StringBuffer`**: Legacy synchronized classes — use `ArrayList`, `HashMap`, `StringBuilder` - **`finalize()`**: Deprecated, unpredictable. Use `Cleaner` or try-with-resources - **No explicit charset in String.getBytes()**: Platform-dependent. Always `getBytes(StandardCharsets.UTF_8)` ## Performance Patterns - `StringBuilder` for concatenation in loops (not `+` operator) - `record` for lightweight data carriers (no boilerplate, value-based) - `ConcurrentHashMap` over synchronized maps for concurrent access - `ZGC` or `Shenandoah` for sub-millisecond GC pauses (Java 17+) - Flyweight pattern for repeated small objects (Integer cache, custom pools) - Off-heap storage with `ByteBuffer.allocateDirect` for large caches - `var` keyword doesn't affect performance but reduces noise - Profile with async-profiler before optimizing — JVM is already very good - Use `--enable-preview` in development to test upcoming features (pattern matching, string templates) ## Virtual Threads & Structured Concurrency (Java 21+) Virtual threads (Project Loom) enable lightweight concurrency without the complexity of reactive frameworks. Create via `Thread.ofVirtual().start(task)` or `Executors.newVirtualThreadPerTaskExecutor()`. Each virtual thread is a Java object (~200 bytes), not an OS thread (~1MB). Use for I/O-bound workloads: HTTP calls, database queries, file I/O. Structured Concurrency (`StructuredTaskScope`) ensures all subtasks complete or are cancelled together. Usage: `try (var scope = new StructuredTaskScope.ShutdownOnFailure())` creates a scope, `scope.fork(callable)` submits tasks, `scope.join()` waits for all, `scope.throwIfFailed()` propagates first error, `scope.result()` returns successful results. Anti-pattern: pinning virtual threads with `synchronized` blocks. Use `ReentrantLock` when virtual threads are involved. Pin detection: JVM logs "Thread X pinned" — investigate and fix. ## Modern Bean Validation & Error Handling Use Jakarta Bean Validation 3.0+ for input validation instead of manual if/else chains. Annotations on records/POJOs: `@NotBlank`, `@Email`, `@Positive`, `@Size(min=1, max=100)`, `@Pattern(regexp="...")`. Group validation: separate Create vs Update validation rules. Custom validators: implement `ConstraintValidator<Annotation, Type>`. Error handling with `@ControllerAdvice` (Spring) or `ExceptionMapper` (JAX-RS): return structured error responses with field-level errors. Pattern: validation exception → `MethodArgumentNotValidException` → extract field errors → `ErrorResponse` with code, message, fieldErrors list. Never return raw stack traces or Hibernate validation errors to clients. ## Testing Strategy Beyond JUnit Modern Java testing requires multiple layers: (a) unit tests with JUnit 5 + AssertJ (fluent assertions), (b) Mockito for mock dependencies, (c) `@SpringBootTest` for integration tests with real DB (Testcontainers), (d) `@WebMvcTest` for controller slice tests, (e) `@DataJpaTest` for repository tests. Testcontainers: write integration tests against real PostgreSQL/MySQL/Redis in Docker containers, not in-memory databases that behave differently. Use `@Testcontainers` annotation and `@Container` fields. Performance: use `@SpringBootTest(webEnvironment = NONE)` to avoid starting the full server for non-HTTP tests. Test slicing: `@JsonTest` for JSON serialization, `@RestClientTest` for REST clients. Mockito best practice: verify interactions, don't just stub — `verify(repository).save(expectedOrder)`. ## JVM Garbage Collection Strategy | GC | Java Version | Best For | Pause Time | |----|-------------|----------|------------| | G1GC | 9+ (default 9-21) | General purpose, balanced | <10ms | | ZGC | 15+ (incubating 11-14) | Large heaps (>100GB), low latency | <1ms | | Shenandoah | 15+ (incubating 12-14) | Concurrent compaction | <1ms | | Serial | All | Small heaps, single core | Longer pauses | | Parallel | All (default 8) | Throughput, batch processing | Longer pauses | GC flags for modern apps: `-XX:+UseZGC -XX:MaxHeapSize=2g -XX:ParallelGCThreads=4 -XX:ConcGCThreads=2`. Monitor GC with `-Xlog:gc*:file=gc.log:time,uptime,tags` and visualize with GCeasy or GCViewer. Heap dump on OOM: `-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/dump.hprof`. Memory leak detection: take 3 heap dumps at intervals, compare with Eclipse MAT for growing object graphs. ## Production Decision Trees ``` Build tool for greenfield project? ├── Spring Boot project → Gradle (Kotlin DSL) — faster incremental builds ├── Standard enterprise → Maven (stable, predictable) └── Android → Gradle (Groovy or Kotlin DSL) ``` ``` Microservices framework? ├── Full Spring ecosystem → Spring Boot + Spring Cloud │ Service discovery: Eureka / Consul │ Config: Spring Cloud Config / Vault ├── Low-resource, fast startup → Quarkus │ GraalVM native: <100ms startup, <10MB RSS │ Suitable for: serverless, high-density containers ├── Reactive, non-blocking → Micronaut │ AOT compilation, compile-time DI │ Suitable for: streaming, real-time
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub