AgentSkillsCN

java-expert

Java 核心设计模式、现代 Java 特性(JDK 17 及以上版本)以及最佳实践

SKILL.md
--- frontmatter
name: java-expert
description: Core Java patterns, modern Java features (JDK 17+), best practices
keywords:
  - java
  - jdk
  - stream
  - lambda
  - record
  - sealed
  - pattern matching
  - virtual threads
  - collections
  - generics
  - concurrency
filePatterns:
  - "*.java"
frameworks:
  - java
  - jdk
tokenCount: 2000
version: 1.0.0

Java Expert Skill

Modern Java development patterns for JDK 17+ enterprise applications. Think, don't copy. Adapt patterns to context.

🎯 Selective Reading Rule

Read ONLY files relevant to the request! Check the content map, find what you need.


📑 Content Map

FileDescriptionWhen to Read
modern-java.mdRecords, sealed classes, pattern matchingNew Java 17+ features
streams.mdStream API patterns, collectorsData processing
concurrency.mdVirtual threads, CompletableFutureAsync operations
collections.mdCollection patterns, immutabilityData structures
exceptions.mdError handling, custom exceptionsException design
testing.mdJUnit 5, Mockito patternsUnit testing

🔑 Core Principles

1. Modern Java Features (JDK 17+)

java
// Records for immutable data
public record User(String id, String name, String email) {
    // Compact constructor for validation
    public User {
        Objects.requireNonNull(id, "id cannot be null");
        Objects.requireNonNull(email, "email cannot be null");
    }
}

// Sealed classes for domain modeling
public sealed interface PaymentMethod 
    permits CreditCard, BankTransfer, Wallet {
}

public record CreditCard(String number, String cvv) implements PaymentMethod {}
public record BankTransfer(String iban) implements PaymentMethod {}
public record Wallet(String walletId) implements PaymentMethod {}

// Pattern matching
public String processPayment(PaymentMethod method) {
    return switch (method) {
        case CreditCard cc -> processCreditCard(cc);
        case BankTransfer bt -> processBankTransfer(bt);
        case Wallet w -> processWallet(w);
    };
}

2. Stream API Best Practices

java
// ✅ GOOD: Clear, readable pipeline
List<UserDto> activeUsers = users.stream()
    .filter(User::isActive)
    .filter(u -> u.getCreatedAt().isAfter(cutoffDate))
    .map(UserDto::fromEntity)
    .sorted(Comparator.comparing(UserDto::name))
    .toList();  // JDK 16+

// ✅ GOOD: Grouping with downstream collector
Map<Department, List<Employee>> byDept = employees.stream()
    .collect(Collectors.groupingBy(
        Employee::getDepartment,
        Collectors.filtering(
            Employee::isActive,
            Collectors.toList()
        )
    ));

// ❌ BAD: Side effects in stream
users.stream()
    .forEach(u -> u.setProcessed(true));  // Side effect!

// ✅ GOOD: Map and collect for transformations
List<User> processed = users.stream()
    .map(u -> u.withProcessed(true))  // Immutable
    .toList();

3. Virtual Threads (JDK 21+)

java
// ✅ GOOD: Virtual threads for I/O-bound tasks
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    List<Future<Result>> futures = tasks.stream()
        .map(task -> executor.submit(() -> processTask(task)))
        .toList();
    
    List<Result> results = futures.stream()
        .map(this::getFutureSafely)
        .toList();
}

// ✅ GOOD: Structured concurrency (JDK 21+)
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
    Supplier<User> user = scope.fork(() -> fetchUser(userId));
    Supplier<List<Order>> orders = scope.fork(() -> fetchOrders(userId));
    
    scope.join().throwIfFailed();
    
    return new UserProfile(user.get(), orders.get());
}

4. Null Safety

java
// ✅ GOOD: Use Optional for potentially absent values
public Optional<User> findById(String id) {
    return Optional.ofNullable(repository.findById(id));
}

// ✅ GOOD: Optional chain
String city = user.flatMap(User::getAddress)
    .map(Address::getCity)
    .orElse("Unknown");

// ❌ BAD: Optional.get() without check
String name = findById(id).get();  // Throws if empty!

// ✅ GOOD: Defensive alternatives
String name = findById(id)
    .map(User::getName)
    .orElseThrow(() -> new UserNotFoundException(id));

✅ Decision Checklist

Before writing Java code:

  • Using JDK 17+ features where appropriate?
  • Records for data classes?
  • Sealed interfaces for closed hierarchies?
  • Optional for nullable returns?
  • Stream API for collections?
  • Virtual threads for I/O operations?
  • Immutability by default?

❌ Anti-Patterns

Anti-PatternWhy BadBetter Approach
Getters/Setters everywhereBreaks encapsulationRecords or builder pattern
Null returnsNPE riskOptional or empty collection
Checked exceptions for control flowPerformance, readabilityReturn types or runtime exceptions
Raw typesType safetyProper generics
Thread.sleep() for timingUnreliableScheduledExecutor or virtual threads

🔗 Related Skills

NeedSkill
Build tools@[skills/maven-gradle]
Unit testing@[skills/testing-junit]