
关于
Spring Boot 和 Quarkus 服务的 Java 编码标准:命名、不可变性、Optional 使用、流、异常、泛型、CDI、响应式模式和项目布局。自动应用框架特定约定。
name: java-coding-standards description: "Java 编码规范,适用于 Spring Boot 和 Quarkus 服务:命名、不可变性、Optional 用法、流、异常、泛型、CDI、响应式模式和项目布局。自动应用框架特定约定。" origin: ECC
Java 编码规范
适用于 Spring Boot 和 Quarkus 服务中可读、可维护的 Java(17+)代码规范。
何时使用
- 在 Spring Boot 或 Quarkus 项目中编写或审查 Java 代码
- 强制执行命名、不可变性或异常处理约定
- 使用 record、sealed class 或模式匹配(Java 17+)
- 审查 Optional、流或泛型的使用
- 组织包结构和项目布局
- [QUARKUS]:使用 CDI 作用域、Panache 实体或响应式管道
工作原理
框架检测
在应用规范之前,从构建文件中确定框架:
- 构建文件包含
quarkus→ 应用 [QUARKUS] 约定 - 构建文件包含
spring-boot→ 应用 [SPRING] 约定 - 两者都未检测到 → 仅应用共享约定
核心原则
- 清晰优于巧妙
- 默认不可变;最小化共享可变状态
- 快速失败并提供有意义的异常
- 一致的命名和包结构
- [QUARKUS]:优先构建时处理而非运行时处理;尽可能避免运行时反射
示例
以下章节展示了 Spring Boot、Quarkus 和共享 Java 的具体示例, 涵盖命名、不可变性、依赖注入、响应式代码、异常、 项目布局、日志、配置和测试。
命名
// PASS: Classes/Records: PascalCase
public class MarketService {}
public record Money(BigDecimal amount, Currency currency) {}
// PASS: Methods/fields: camelCase
private final MarketRepository marketRepository;
public Market findBySlug(String slug) {}
// PASS: Constants: UPPER_SNAKE_CASE
private static final int MAX_PAGE_SIZE = 100;
// PASS: [QUARKUS] JAX-RS resources named as *Resource, not *Controller
public class MarketResource {}
// PASS: [SPRING] REST controllers named as *Controller
public class MarketController {}
不可变性
// PASS: 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
}
// PASS: [QUARKUS] Panache active-record entities use public fields (Quarkus convention)
@Entity
public class Market extends PanacheEntity {
public String name;
public MarketStatus status;
// Panache generates accessors at build time; public fields are idiomatic here
}
// PASS: [QUARKUS] Panache MongoDB entities
@MongoEntity(collection = "markets")
public class Market extends PanacheMongoEntity {
public String name;
public MarketStatus status;
}
Optional 用法
// PASS: Return Optional from find* methods
// [SPRING]
Optional<Market> market = marketRepository.findBySlug(slug);
// [QUARKUS] Panache
Optional<Market> market = Market.find("slug", slug).firstResultOptional();
// PASS: Map/flatMap instead of get()
return market
.map(MarketResponse::from)
.orElseThrow(() -> new EntityNotFoundException("Market not found"));
流最佳实践
// PASS: Use streams for transformations, keep pipelines short
List<String> names = markets.stream()
.map(Market::name)
.filter(Objects::nonNull)
.toList();
// FAIL: Avoid complex nested streams; prefer loops for clarity
依赖注入
// PASS: [SPRING] Constructor injection (preferred over @Autowired on fields)
@Service
public class MarketService {
private final MarketRepository marketRepository;
public MarketService(MarketRepository marketRepository) {
this.marketRepository = marketRepository;
}
}
// PASS: [QUARKUS] Constructor injection
@ApplicationScoped
public class MarketService {
private final MarketRepository marketRepository;
@Inject
public MarketService(MarketRepository marketRepository) {
this.marketRepository = marketRepository;
}
}
// PASS: [QUARKUS] Package-private field injection (acceptable in Quarkus — avoids proxy issues)
@ApplicationScoped
public class MarketService {
@Inject
MarketRepository marketRepository;
}
// FAIL: [SPRING] Field injection with @Autowired
@Autowired
private MarketRepository marketRepository; // use constructor injection
// FAIL: [QUARKUS] @Singleton when interception or lazy init is needed
@Singleton // non-proxyable — use @ApplicationScoped instead
public class MarketService {}
响应式模式 [QUARKUS]
// PASS: Return Uni/Multi from reactive endpoints
@GET
@Path("/{slug}")
public Uni<Market> findBySlug(@PathParam("slug") String slug) {
return Market.find("slug", slug)
.<Market>firstResult()
.onItem().ifNull().failWith(() -> new MarketNotFoundException(slug));
}
// PASS: Non-blocking pipeline composition
兼容工具
Claude CodeCursor
标签
前端开发
