Skip to main content

java-modern

Java 21+ features for Spring Boot - records, sealed classes, pattern matching, virtual threads, text blocks. Use when user asks about modern Java, Java 21 features, or when modernizing existing code.

来源信息

仓库
piomin/claude-ai-spring-boot
最近来源活动
2026年10月18日 09:39
检测到的 SKILL.md 语言
英语
星标
1,430
Forks
448

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
name
java-modern
description
Java 21+ features for Spring Boot - records, sealed classes, pattern matching, virtual threads, text blocks. Use when user asks about modern Java, Java 21 features, or when modernizing existing code.
# Java Modern Skill Java 21+ language features and how to use them in Spring Boot applications. ## When to Use - Building new Spring Boot 4.x applications (default to modern features) - Modernizing/refactoring existing Java code - User asks about records, sealed classes, pattern matching, virtual threads --- ## Records (Java 16+) ### DTOs ```java // ✅ Records for request/response DTOs public record ProductRequest( @NotBlank String name, @DecimalMin("0.0") BigDecimal price ) {} public record ProductResponse( Long id, String name, BigDecimal price, LocalDateTime createdAt ) { public static ProductResponse from(Product entity) { return new ProductResponse( entity.getId(), entity.getName(), entity.getPrice(), entity.getCreatedAt() ); } } ``` ### Configuration Properties ```java // ✅ Records for config properties (Spring Boot 4.x) @ConfigurationProperties(prefix = "app.notification") public record NotificationProperties( boolean enabled, String fromEmail, Duration timeout, Retry retry ) { public record Retry(int maxAttempts, Duration delay) {} } ``` ### When NOT to use records - JPA entities (Hibernate needs mutable objects, no-arg constructor) - Classes that need inheritance - Objects with mutable state --- ## Sealed Classes (Java 17+) ### Domain Modeling ```java // ✅ Restrict payment types at compile time public sealed interface PaymentResult permits PaymentSuccess, PaymentFailure, PaymentPending { } public record PaymentSuccess(String transactionId, BigDecimal amount) implements PaymentResult {} public record PaymentFailure(String errorCode, String message) implements PaymentResult {} public record PaymentPending(String referenceId) implements PaymentResult {} // Usage in service public PaymentResult processPayment(PaymentRequest request) { try { String txId = gateway.charge(request); return new PaymentSuccess(txId, request.amount()); } catch (InsufficientFundsException e) { return new PaymentFailure("INSUFFICIENT_FUNDS", e.getMessage()); } } ``` ### Event Hierarchies ```java public sealed interface OrderEvent permits OrderCreated, OrderShipped, OrderCancelled { Long orderId(); LocalDateTime timestamp(); } public record OrderCreated(Long orderId, LocalDateTime timestamp, Long customerId) implements OrderEvent {} public record OrderShipped(Long orderId, LocalDateTime timestamp, String trackingNumber) implements OrderEvent {} public record OrderCancelled(Long orderId, LocalDateTime timestamp, String reason) implements OrderEvent {} ``` --- ## Pattern Matching ### instanceof (Java 16+) ```java // ❌ Old style if (obj instanceof String) { String s = (String) obj; return s.length(); } // ✅ Pattern matching if (obj instanceof String s) { return s.length(); } ``` ### switch (Java 21+) ```java // ✅ Exhaustive switch with sealed types - compiler enforces all cases public String handlePayment(PaymentResult result) { return switch (result) { case PaymentSuccess s -> "Paid: " + s.transactionId(); case PaymentFailure f -> "Failed: " + f.message(); case PaymentPending p -> "Pending: " + p.referenceId(); }; } // ✅ Guarded patterns public BigDecimal calculateDiscount(Order order) { return switch (order) { case Order o when o.getTotal().compareTo(new BigDecimal("100")) > 0 -> o.getTotal().multiply(new BigDecimal("0.10")); case Order o when o.isLoyaltyMember() -> o.getTotal().multiply(new BigDecimal("0.05")); default -> BigDecimal.ZERO; }; } ``` ### In Service Logic ```java // Replacing if-else chains with pattern matching public String processNotification(Object event) { return switch (event) { case OrderCreated o when o.total().compareTo(BigDecimal.valueOf(1000)) > 0 -> sendPriorityNotification(o); case OrderCreated o -> sendStandardNotification(o); case OrderCancelled c -> sendCancellationNotification(c); case PaymentReceived p -> sendPaymentConfirmation(p); default -> throw new IllegalArgumentException("Unknown event: " + event); }; } // Pattern matching with instanceof — no more casting public BigDecimal calculateShipping(Address address) { if (address instanceof DomesticAddress d) { return d.isExpressZone() ? DOMESTIC_EXPRESS : DOMESTIC_STANDARD; } else if (address instanceof InternationalAddress i) { return BASE_INTERNATIONAL.multiply(i.distanceFactor()); } throw new IllegalArgumentException("Unknown address type"); } ``` ### In Exception Handlers ```java @RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) public ResponseEntity<ErrorResponse> handle(Exception ex) { return switch (ex) { case EntityNotFoundException e -> ResponseEntity.status(404).body(new ErrorResponse(e.getMessage())); case DataIntegrityViolationException e -> ResponseEntity.status(409).body(new ErrorResponse("Duplicate entry")); case ConstraintViolationException e -> ResponseEntity.badRequest().body(new ErrorResponse(e.getMessage())); default -> ResponseEntity.internalServerError().body(new ErrorResponse("Unexpected error")); }; } } ``` --- ## Virtual Threads (Java 21 + Spring Boot 4.x) ```yaml # application.yml - enables virtual threads for all request handling spring: threads: virtual: enabled: true ``` This single property: - Runs each HTTP request on a virtual thread (Tomcat) - Makes `@Async` methods use virtual threads - Allows blocking I/O (JDBC, RestClient) to scale like reactive code ```java // ✅ Blocking code scales with virtual threads - no code changes needed @Service @Transactional(readOnly = true) public class ReportService { private final OrderRepository orderRepository; private final RestClient externalApi; public ReportService(OrderRepository orderRepository, RestClient externalApi) { this.orderRepository = orderRepository; this.externalApi = externalApi; } public Report generate(Long customerId) { // Both blocking calls - on virtual threads this scales to thousands of concurrent requests List<Order> orders = orderRepository.findByCustomerId(customerId); CustomerData data = externalApi.get() .uri("/customers/{id}", customerId) .retrieve() .body(CustomerData.class); return new Report(orders, data); } } ``` **Do NOT use with virtual threads:** - `synchronized` blocks holding across blocking calls (use `ReentrantLock` instead) - Thread-local heavy frameworks (check compatibility first) --- ## Text Blocks (Java 15+) ```java // ✅ JPQL queries @Query(""" SELECT p FROM Product p WHERE p.active = true AND p.price BETWEEN :minPrice AND :maxPrice ORDER BY p.name """) List<Product> findActiveInPriceRange( @Param("minPrice") BigDecimal min, @Param("maxPrice") BigDecimal max); // ✅ JSON in tests mockMvc.perform(post("/api/v1/products") .contentType(MediaType.APPLICATION_JSON) .content(""" { "name": "Widget", "price": 10.00 } """)) .andExpect(status().isCreated()); ``` --- ## Sequenced Collections (Java 21) `SequencedCollection` adds `getFirst()`, `getLast()`, and `reversed()` to ordered collections. ```java // ❌ Before Java 21 String first = list.get(0); String last = list.get(list.size() - 1); // ✅ Java 21+ String first = list.getFirst(); String last = list.getLast(); // Reversed view (no copy) for (var item : list.reversed()) { process(item); } // Works with all ordered collections: List, Deque, SortedSet, LinkedHashSet, LinkedHashMap SortedSet<User> users = userRepository.findTopByOrderByCreatedAtDesc(); User newest = users.getFirst(); User oldest = users.getLast(); ``` --- ## Quick Decision Guide | Feature | Use For | Avoid When | |---------|---------|------------| | **Records** | DTOs, config, value objects | JPA entities, mutable state | | **Sealed classes** | Closed type hierarchies, domain events | Open extension needed | | **Pattern matching switch** | Handling sealed types, replacing if-else chains | Simple equality checks | | **Virtual threads** | High-concurrency blocking I/O | CPU-bound work, `synchronized` over I/O | | **Text blocks** | JPQL queries, JSON test data, SQL | Single-line strings | | **SequencedCollections** | First/last access on ordered collections | Unordered sets/maps |
在 GitHub 查看