java-coding-standards

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Java Coding Standards

Java编码规范

Standards for readable, maintainable Java (17+) code in Spring Boot services.
适用于Spring Boot服务中可读性强、可维护的Java 17+代码的规范。

When to Activate

适用场景

  • Writing or reviewing Java code in Spring Boot projects
  • Enforcing naming, immutability, or exception handling conventions
  • Working with records, sealed classes, or pattern matching (Java 17+)
  • Reviewing use of Optional, streams, or generics
  • Structuring packages and project layout
  • 编写或评审Spring Boot项目中的Java代码
  • 推行命名、不可变性或异常处理约定
  • 处理records、sealed classes或pattern matching(Java 17+)相关代码
  • 评审Optional、流或泛型的使用
  • 规划包结构与项目布局

Core Principles

核心原则

  • Prefer clarity over cleverness
  • Immutable by default; minimize shared mutable state
  • Fail fast with meaningful exceptions
  • Consistent naming and package structure
  • 优先清晰而非炫技
  • 默认不可变,最小化共享可变状态
  • 快速失败并抛出有意义的异常
  • 命名和包结构保持一致

Naming

命名规范

java
// ✅ 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;
java
// ✅ 类/Records:大驼峰命名法
public class MarketService {}
public record Money(BigDecimal amount, Currency currency) {}

// ✅ 方法/字段:小驼峰命名法
private final MarketRepository marketRepository;
public Market findBySlug(String slug) {}

// ✅ 常量:大写蛇形命名法
private static final int MAX_PAGE_SIZE = 100;

Immutability

不可变性

java
// ✅ 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
}
java
// ✅ 优先使用records和final字段
public record MarketDto(Long id, String name, MarketStatus status) {}

public class Market {
  private final Long id;
  private final String name;
  // 仅提供getter,不提供setter
}

Optional Usage

Optional使用规范

java
// ✅ 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"));
java
// ✅ 从find*方法返回Optional
Optional<Market> market = marketRepository.findBySlug(slug);

// ✅ 使用map/flatMap而非get()
return market
    .map(MarketResponse::from)
    .orElseThrow(() -> new EntityNotFoundException("Market not found"));

Streams Best Practices

流的最佳实践

java
// ✅ 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
java
// ✅ 使用流进行转换,保持流水线简短
List<String> names = markets.stream()
    .map(Market::name)
    .filter(Objects::nonNull)
    .toList();

// ❌ 避免复杂的嵌套流;优先使用循环以保证清晰性

Exceptions

异常处理

  • Use unchecked exceptions for domain errors; wrap technical exceptions with context
  • Create domain-specific exceptions (e.g.,
    MarketNotFoundException
    )
  • Avoid broad
    catch (Exception ex)
    unless rethrowing/logging centrally
java
throw new MarketNotFoundException(slug);
  • 领域错误使用非受检异常;为技术异常添加上下文包装
  • 创建领域特定的异常(例如
    MarketNotFoundException
  • 除非在集中式处理中重新抛出或记录,否则避免宽泛的
    catch (Exception ex)
    捕获
java
throw new MarketNotFoundException(slug);

Generics and Type Safety

泛型与类型安全

  • Avoid raw types; declare generic parameters
  • Prefer bounded generics for reusable utilities
java
public <T extends Identifiable> Map<Long, T> indexById(Collection<T> items) { ... }
  • 避免原始类型;声明泛型参数
  • 优先使用有界泛型实现可复用工具类
java
public <T extends Identifiable> Map<Long, T> indexById(Collection<T> items) { ... }

Project Structure (Maven/Gradle)

项目结构(Maven/Gradle)

src/main/java/com/example/app/
  config/
  controller/
  service/
  repository/
  domain/
  dto/
  util/
src/main/resources/
  application.yml
src/test/java/... (mirrors main)
src/main/java/com/example/app/
  config/
  controller/
  service/
  repository/
  domain/
  dto/
  util/
src/main/resources/
  application.yml
src/test/java/... (mirrors main)

Formatting and Style

格式与风格

  • Use 2 or 4 spaces consistently (project standard)
  • One public top-level type per file
  • Keep methods short and focused; extract helpers
  • Order members: constants, fields, constructors, public methods, protected, private
  • 统一使用2或4个空格缩进(遵循项目标准)
  • 每个文件仅包含一个公开的顶层类型
  • 保持方法简短且聚焦;提取辅助方法
  • 成员顺序:常量、字段、构造函数、公开方法、受保护方法、私有方法

Code Smells to Avoid

需要避免的代码坏味道

  • Long parameter lists → use DTO/builders
  • Deep nesting → early returns
  • Magic numbers → named constants
  • Static mutable state → prefer dependency injection
  • Silent catch blocks → log and act or rethrow
  • 长参数列表 → 使用DTO/构建器
  • 深层嵌套 → 提前返回
  • 魔法值 → 使用命名常量
  • 静态可变状态 → 优先使用依赖注入
  • 静默捕获块 → 记录日志并处理或重新抛出

Logging

日志记录

java
private static final Logger log = LoggerFactory.getLogger(MarketService.class);
log.info("fetch_market slug={}", slug);
log.error("failed_fetch_market slug={}", slug, ex);
java
private static final Logger log = LoggerFactory.getLogger(MarketService.class);
log.info("fetch_market slug={}", slug);
log.error("failed_fetch_market slug={}", slug, ex);

Null Handling

空值处理

  • Accept
    @Nullable
    only when unavoidable; otherwise use
    @NonNull
  • Use Bean Validation (
    @NotNull
    ,
    @NotBlank
    ) on inputs
  • 仅在不可避免时接受
    @Nullable
    ;否则使用
    @NonNull
  • 在输入上使用Bean Validation(
    @NotNull
    @NotBlank

Testing Expectations

测试要求

  • JUnit 5 + AssertJ for fluent assertions
  • Mockito for mocking; avoid partial mocks where possible
  • Favor deterministic tests; no hidden sleeps
Remember: Keep code intentional, typed, and observable. Optimize for maintainability over micro-optimizations unless proven necessary.
  • 使用JUnit 5 + AssertJ进行流畅断言
  • 使用Mockito进行模拟;尽可能避免部分模拟
  • 优先确定性测试;不要使用隐藏的休眠操作
注意:代码应具备明确意图、强类型且可观测。优先优化可维护性而非微性能,除非有明确必要。