claude-code/claude-zh/skills/java-coding-standards/SKILL.md

147 lines
4.8 KiB
Markdown
Raw Normal View History

2026-02-27 13:45:37 +00:00
---
name: java-coding-standards
description: 針對 Spring Boot 服務的 Java 編碼標準包含命名規範、不可變性、Optional 使用、串流 (Streams)、例外處理、泛型以及專案結構。
---
# Java 編碼標準 (Java Coding Standards)
適用於 Spring Boot 服務中可讀且易於維護的 Java (17+) 程式碼標準。
## 何時啟用
- 在 Spring Boot 專案中編寫或審查 Java 程式碼。
- 執行有關命名、不可變性或例外處理的慣例。
- 使用 Records、Sealed Classes 或模式匹配 (Pattern Matching) (Java 17+)。
- 審查 Optional、串流或泛型的使用。
- 規劃套件結構與專案佈局。
## 核心原則
- **清晰重於取巧**:程式碼應易於理解。
- **預設不可變**:盡可能減少共享的可變狀態。
- **儘早報錯 (Fail Fast)**:拋出具備明確語義的例外。
- **一致性**:保持命名與套件結構的一致性。
## 命名規範
```java
// ✅ 類別 (Classes) / RecordsPascalCase (大駝峰)
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)
```java
// ✅ 優先使用 Records 與 final 欄位
public record MarketDto(Long id, String name, MarketStatus status) {}
public class Market {
private final Long id;
private final String name;
// 僅提供 Getters不提供 Setters
}
```
## Optional 的使用
```java
// ✅ find* 方法應回傳 Optional
Optional<Market> market = marketRepository.findBySlug(slug);
// ✅ 使用 map/flatMap 而非直接 get()
return market
.map(MarketResponse::from)
.orElseThrow(() -> new EntityNotFoundException("找不到指定的市場資料"));
```
## 串流 (Streams) 最佳實踐
```java
// ✅ 使用串流進行轉換,保持細節簡潔,避免過長的鏈結
List<String> names = markets.stream()
.map(Market::name)
.filter(Objects::nonNull)
.toList();
// ❌ 避免過於複雜的嵌套串流;為了清晰起見,迴圈有時是更好的選擇
```
## 例外處理 (Exceptions)
- 針對領域錯誤使用未檢查例外 (Unchecked Exceptions);將技術性例外封裝並補足上下文。
- 建立領域特定的例外(例如:`MarketNotFoundException`)。
- 避免使用廣泛的 `catch (Exception ex)`,除非是為了在中心位置重新拋出或記錄。
```java
throw new MarketNotFoundException(slug);
```
## 泛型與型別安全
- 避免使用原始型別 (Raw Types);務必宣告泛型參數。
- 在開發可重用的工具型函式時,優先考慮有界泛型 (Bounded Generics)。
```java
public <T extends Identifiable> Map<Long, T> indexById(Collection<T> items) { ... }
```
## 專案結構 (Maven/Gradle)
```
src/main/java/com/example/app/
config/ # 配置類別
controller/ # REST API 控制器
service/ # 業務邏輯服務
repository/ # 資料存取層
domain/ # 實體與領域模型
dto/ # 資料傳輸物件
util/ # 工具類別
src/main/resources/
application.yml
src/test/java/... (與 main 目錄結構映射)
```
## 格式與風格
- 專案內必須一致使用 2 個或 4 個空格進行縮排。
- 每個檔案僅定義一個公開的頂層型別。
- 保持方法短小且聚焦於單一功能;適時提取輔助方法 (Helpers)。
- 成員排序:常數、欄位、建構子、公開方法、受保護方法、私有方法。
## 應避免的程式碼壞味道 (Code Smells)
- **過長的參數列表**:應改用 DTO 或建構者模式 (Builder)。
- **深層嵌套**:優先使用提早回傳 (Early Returns)。
- **魔術數字**:應改用具名的常數。
- **靜態可變狀態**:優先考慮使用依賴注入 (Dependency Injection)。
- **安靜的 Catch 塊**:必須記錄日誌並採取行動,或重新拋出。
## 日誌紀錄 (Logging)
```java
private static final Logger log = LoggerFactory.getLogger(MarketService.class);
log.info("擷取市場資料 slug={}", slug);
log.error("擷取市場資料失敗 slug={}", slug, ex);
```
## 空值 (Null) 處理
- 僅在不可避免時接受 `@Nullable`;否則應預設使用 `@NonNull`
- 在輸入端使用 Bean Validation`@NotNull`, `@NotBlank`)。
## 測試期望
- 使用 JUnit 5 與 AssertJ 進行流暢的斷言 (Fluent Assertions)。
- 使用 Mockito 進行 Mock盡可能避免使用部分 Mock (Partial Mocks)。
- 追求確定性的測試;不要在測試中使用隱含的休眠 (Sleep)。
**請記住**:保持程式碼具備意圖性、強型別且可觀察。在證明有必要進行微觀技術優化之前,應優先優化維護性。