Java (17+) coding standards for readable, maintainable code in Spring Boot services.
When to Activate (When to Activate)
- When writing or reviewing Java code in Spring Boot projects
- When enforcing naming, immutability, or exception handling conventions
- When using records, sealed classes, or pattern matching (Java 17+)
- When reviewing the use of Optional, streams, or generics
- When planning package structure and project layout
Core Principles (Core Principles)
- Clarity over cleverness
- Immutable by default; minimize shared mutable state
- Fail fast and provide meaningful exception messages
- Maintain consistency in naming and package structure
Naming (Naming)
// ✅ 类/Records:大驼峰(PascalCase)
public class MarketService {}
public record Money(BigDecimal amount, Currency currency) {}
// ✅ 方法/字段:小驼峰(camelCase)
private final MarketRepository marketRepository;
public Market findBySlug(String slug) {}
// ✅ 常量:全大写蛇形(UPPER_SNAKE_CASE)
private static final int MAX_PAGE_SIZE = 100;
Immutability (Immutability)
// ✅ 优先使用 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 Usage)
// ✅ 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 (Streams Best Practices)
// ✅ 使用流进行转换,保持流水线简短
List<String> names = markets.stream()
.map(Market::name)
.filter(Objects::nonNull)
.toList();
// ❌ 避免复杂的嵌套流;为了清晰起见,优先使用循环
Exception Handling (Exceptions)
- Use unchecked exceptions for domain errors; wrap technical exceptions with context
- Create domain-specific exceptions (e.g.
MarketNotFoundException) - Avoid catching broad
catch (Exception ex), unless rethrowing or logging at a central location
throw new MarketNotFoundException(slug);
Generics and Type Safety (Generics and Type Safety)
- Avoid raw types; declare generic parameters explicitly
- Prefer bounded generics for reusable utility classes
public <T extends Identifiable> Map<Long, T> indexById(Collection<T> items) { ... }
Project Structure (Project Structure - Maven/Gradle)
src/main/java/com/example/app/
config/
controller/
service/
repository/
domain/
dto/
util/
src/main/resources/
application.yml
src/test/java/... (与 main 结构镜像)
Formatting and Style (Formatting and Style)
- Use 2 or 4 spaces consistently (follow project standards)
- Include only one public top-level type per file
- Keep methods short and focused; extract helper methods
- Member ordering: constants, fields, constructors, public methods, protected methods, private methods
Code Smells to Avoid (Code Smells to Avoid)
- Excessively long parameter lists → use DTOs/builders
- Deeply nested hierarchies → early returns
- Magic numbers → named constants
- Static mutable state → prefer dependency injection
- Silent catch blocks → log and handle or rethrow
Logging (Logging)
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 (Null Handling)
- Accept only when unavoidable
@Nullable; otherwise use@NonNull - Use Bean Validation for inputs (e.g.
@NotNull,@NotBlank)
Testing Expectations (Testing Expectations)
- Use JUnit 5 + AssertJ for fluent assertions
- Use Mockito for mocks; avoid partial mocks where possible
- Prefer deterministic tests; strictly prohibit hidden sleep waits
Remember: Keep code intentional, strongly typed, and observable. Unless proven otherwise, prioritize maintainability over micro-optimizations.