name: java-coding-standards description: 适用于Spring Boot服务的Java编码标准:命名、不变性、Optional使用、流、异常、泛型、项目布局。
Java编码标准
Spring Boot服务中编写可读且可维护的Java(17+)代码的标准。
核心原则
- 优先考虑清晰性而非巧妙性
- 默认不可变;最小化共享可变状态
- 通过有意义的异常尽早失败
- 一致的命名和包结构
命名
// ✅ 类/记录: 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;
不变性
// ✅ 优先使用record和final字段
public record MarketDto(Long id, String name, MarketStatus status) {}
public class Market {
private final Long id;
private final String name;
// 只有getter,没有setter
}
Optional的使用
// ✅ find*方法返回Optional
Optional<Market> market = marketRepository.findBySlug(slug);
// ✅ 使用map/flatMap代替get()
return market
.map(MarketResponse::from)
.orElseThrow(() -> new EntityNotFoundException("Market not found"));
流的最佳实践
// ✅ 使用流进行转换,并保持管道简短
List<String> names = markets.stream()
.map(Market::name)
.filter(Objects::nonNull)
.toList();
// ❌ 避免复杂的嵌套流;为了清晰性优先使用循环
异常
- 对于领域错误使用非检查异常;技术异常需附带上下文包装
- 创建领域特定的异常(例如:
MarketNotFoundException) - 避免宽泛的
catch (Exception ex)(除非在中心位置重新抛出/记录日志)
throw new MarketNotFoundException(slug);
泛型和类型安全
- 避免原始类型;声明泛型参数
- 对于可重用的工具类,优先使用有界泛型
public <T extends Identifiable> Map<Long, T> indexById(Collection<T> items) { ... }
项目结构(Maven/Gradle)
src/main/java/com/example/app/
config/
controller/
service/
repository/
domain/
dto/
util/
src/main/resources/
application.yml
src/test/java/... (镜像main结构)
格式和风格
- 一致地使用2或4个空格(遵循项目标准)
- 每个文件一个public顶级类型
- 保持方法简短且专注;提取辅助方法
- 成员顺序:常量、字段、构造函数、public方法、protected、private
应避免的代码异味
- 长参数列表 → 使用DTO/构建器
- 深层嵌套 → 尽早返回
- 魔法数字 → 使用命名常量
- 静态可变状态 → 优先使用依赖注入
- 静默的catch块 → 记录日志并采取行动,或重新抛出
日志记录
private static final Logger log = LoggerFactory.getLogger(MarketService.class);
log.info("fetch_market slug={}", slug);
log.error("failed_fetch_market slug={}", slug, ex);
Null处理
- 仅在必要时接受
@Nullable;否则使用@NonNull - 对输入使用Bean Validation(
@NotNull、@NotBlank)
测试期望
- 使用JUnit 5 + AssertJ进行流畅的断言
- 使用Mockito进行模拟;尽可能避免部分模拟
- 优先使用确定性测试;避免隐藏的sleep
记住:保持代码意图明确、类型安全且可观察。在可维护性得到证明之前,优先考虑可维护性而非微优化。