### [lombok](https://kucw.github.io/blog/2020/3/java-lombok/)
pom.xml
```xml
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
<scope>provided</scope>
</dependency>
```
build.gradle
```groovy
repositories {
mavenCentral()
}
dependencies {
compileOnly 'org.projectlombok:lombok:1.18.26'
annotationProcessor 'org.projectlombok:lombok:1.18.26'
testCompileOnly 'org.projectlombok:lombok:1.18.26'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.26'
}
```
## @Data
```java
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer id;
private String name;
}
```
same
```java
@Getter
@Setter
@ToString
@EqualsAndHashCode
@RequiredArgsConstructor
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer id;
private String name;
}
```
---
## @Builder
下面是一個使用lombok的@Builder註釋的範例:
```java
import lombok.Builder;
import lombok.Getter;
@Getter
@Builder
public class User {
private String name;
private int age;
private String email;
}
public class Main {
public static void main(String[] args) {
User user = User.builder()
.name("Alice")
.age(25)
.email("alice@example.com")
.build();
System.out.println("Name: " + user.getName());
System.out.println("Age: " + user.getAge());
System.out.println("Email: " + user.getEmail());
}
}
```
在這個範例中,我們使用@Builder註釋來自動生成一個builder模式的建造者類,讓我們可以方便地創建對象。在Main類中,我們使用User.builder()方法來創建User對象,然後使用builder()方法設置屬性的值,最後使用build()方法來建構User對象。
---
## @SneakyThrows
### 💻 實戰演練:怎麼用?前後對比給你看
我們以最常拋出 `UnsupportedEncodingException`(受檢異常)的 URL 編碼為例:
#### ❌ 傳統寫法(被 try-catch 搞得支離破碎)
```java
// 只是想做個 URL 編碼,程式碼就被迫長出厚厚的腫瘤
public String encodeUrlTraditional(String text) {
try {
return URLEncoder.encode(text, "UTF-8"); // 👈 這行會拋出受檢異常
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e); // 逼得你必須手動轉成 RuntimeException
}
}
```
#### ⭕ 現代優雅寫法:使用 `@SneakyThrows`
```java
import lombok.SneakyThrows;
// 😎 乾淨、清爽、直接一行流
@SneakyThrows
public String encodeUrlModern(String text) {
return URLEncoder.encode(text, "UTF-8"); // 👈 編譯器直接放行,再也不會嗶嗶叫!
}
```
#### 🌟 進階玩法:精準防禦(推薦寫法)
如果你不希望所有的異常都被矇混過去,只希望針對「特定的受檢異常」放行,你可以把異常的 Class 當作參數傳給它:
```java
@SneakyThrows(UnsupportedEncodingException.class)
public String encodeUrlStrict(String text) {
return URLEncoder.encode(text, "UTF-8");
}
```
```java
// 🌟 完美點名:同時欺騙編譯器放行「編碼異常」與「資料庫異常」
@SneakyThrows({UnsupportedEncodingException.class, SQLException.class})
public String processLegacyData(String rawData) {
// 1. 可能拋出 UnsupportedEncodingException (受檢)
String decoded = java.net.URLDecoder.decode(rawData, "UTF-8");
// 2. 可能拋出 SQLException (受檢)
String dbResult = jdbcTool.queryData(decoded);
return dbResult;
}
```
---
## @Accessors
### 🎯 直擊核心
它是 Lombok 家族中的「美學大師」,專門用來顛覆 Java 傳統的 `set / get` 語法,幫你開啟「流式鏈式呼叫(Fluent / Chain)」的語法糖!
在標準的 Java Bean 規範中,當你對一個物件賦值時,語法通常非常呆板、枯燥:
```java
User user = new User();
user.setName("Gemini");
user.setAge(18);
user.setAddress("Taipei");
```
這種一行一個 `set` 的寫法,會強迫程式碼像階梯一樣往垂直方向瘋狂延伸。而 `@Accessors` 的唯一作用,就是**重新定義 Getter 與 Setter 的生成骨架**,讓你能寫出像 JavaScript、流式 API(Stream)那樣極致流暢的一行流代碼!
---
### 🔍 深度拆解:它最經典的「三大核心參數」
`@Accessors` 通常會跟 `@Data` 或 `@Getter / @Setter` 搭配使用。它有三個非常強大的屬性設定,能徹底改變你實體物件(Entity/DTO)的長相:
#### 1. `chain = true`(商用高頻最愛 🌟)
* **技術原理**:傳統的 `set` 方法回傳型態是 `void`(丟進去就沒了)。當你開啟 `chain = true`,Lombok 會在編譯期把所有 `set` 方法改造成「回傳 `this`(物件本身)」!
* **語法神效**:
```java
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true) // 🌟 開啟鏈式流
public class User {
private String name;
private int age;
}
// === 呼叫端直接高潮,一行收工 ===
User user = new User().setName("Gemini").setAge(18);
```
#### 2. `fluent = true`(極簡主義者的最愛 🚀)
* **技術原理**:它嫌 `get` 和 `set` 這五個英文字母太累贅。開啟 `fluent = true` 後,它生成的 Getter/Setter 會**徹底消滅 `get` 與 `set` 前綴**,直接用「欄位名稱」當作方法名。
* **注意**:它天生就自帶 `chain = true` 的效果。
* **語法神效**:
```java
@Data
@Accessors(fluent = true) // 🚀 開啟極簡流
public class User {
private String name;
private int age;
}
// === 賦值與取值,徹底告別 get/set 前綴 ===
User user = new User().name("Gemini").age(18); // 這是在 set
String name = user.name(); // 這是在 get!
```
#### 3. `prefix = "..."`(老舊資料庫欄位的解毒劑 🛠️)
* **技術原理**:有時候公司的舊資料庫非常囉唆,欄位天生自帶前綴(例如 `p_name`、`p_age`,代表 private)。但你希望在 Java 程式碼裡面呼叫時是乾淨的 `getName()`、`getAge()`。
* **語法神效**:
```java
@Data
@Accessors(prefix = "p") // 🛠️ 自動過濾 "p" 前綴
public class Product {
private Long pId;
private String pName;
}
// === 呼叫端完全感受不到噁心的資料庫前綴 ===
Product product = new Product();
product.setId(1001L); // 自動對應到 pId
product.setName("Apple"); // 自動對應到 pName
```
---
### ⚠️ 誠實警告
爽用美學時,必須防禦的三大「商用巨坑」
雖然 `@Accessors(chain = true)` 寫起來爽度破表,但在大型專案(尤其是涉及大量框架反射)中,它埋下了三個可能讓你加班到深夜的致命隱憂:
1. **傳統 Bean 複製工具直接變「瞎子」(如 BeanUtils)**:
像是 Apache 的 `BeanUtils.copyProperties()` 或一些老舊的 DTO 轉換工具,它們的底層邏輯非常死板:**「認定 Setter 方法的回傳值必須是 `void`」**。一旦你加了 `chain = true` 讓 Setter 回傳了 `this`,這些工具在反射時會直接判定這個物件「沒有標準的 Setter」,導致**欄位全部複製失敗,通通變成 null**!(商用環境建議改用現代的 MapStruct,它完美支援鏈式物件)。
2. **與 JSON 序列化框架的相容性考驗**:
當你開啟 `fluent = true`,Getter 變成了 `user.name()`。某些極度老舊的 JSON 序列化套件(如十幾年前的 Jackson 舊版本或某些奇葩的 XML 解析器),在把物件轉成 JSON 字串時,會死板地去掃描 `getXXX` 方法。因為你把 `get` 刪光了,它可能會判定這個物件沒有任何欄位,最後**轉出一個空 JSON `{}**`。
3. **可讀性混淆(特別是 `fluent = true`)**:
在 Code Review 時,看到 `user.age()`,新來的同事可能會一頭霧水:「這行到底是在取值,還是在設定值?」必須看它有沒有帶參數才能判斷,這在大型團隊中會增加一絲絲的溝通成本。
---