前面在介紹使用 Spring Data JPA 的時候,在關聯的部分有碰到一些使用 Lombok 的問題,這篇就來介紹一下個別的註解作用,也可以讓大家使用的時候也知道背後運作的邏輯。
Lombok 是一個套件可以幫助我們定義物件時省去許多重複冗長的 code ,可以大幅提升開發效率,下面是常見的註解。
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
小補充: 其實有很多方法如果是用 Intellij 都可以在物件內點選右鍵使用 generate 產生,但是如果可以用一個註解就解決這些還是來得方便很多,但建議剛開始新手可以先用這些 generate 來產生對應方法,也可以藉此了解每個註解背後的原始 code 是怎麼運作。
進行物件導向的撰寫必備的方法,用來取得或修改物件屬性
@Getter
@Setter
public class product {
private Integer id;
private String name;
}
(原始定義方法) 效果同上
public class product {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
自動 override toString()
方法,使用時會印出所有屬性
@ToString
public class product {
private Integer id;
private String name;
}
(註解生效原始碼) 效果同上
public class product {
private Integer id;
private String name;
public String toString() {
return "Product{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
起始子 (Constructor) 的創建,有三種註解是根據創建時是否包含內部屬性作為參數來決定。
例如有個 product 有 id, name 的屬性
@AllArgsConstructor
public class product {
private Integer id;
private String name;
}
(註解生效原始碼) 效果同上,使用註解表示我們獲得一個創建物件時可以帶入這些屬性並賦予值的方法
public class product {
private Integer id;
private String name;
public Product(Integer id, String name) {
this.id = id;
this.name = name;
}
}
@NoArgsConstructor
public class product {
private Integer id;
private String name;
}
(註解生效原始碼) 效果同上,創建時就只是建立出空的物件,但沒辦法帶入任何屬性
public class product {
private Integer id;
private String name;
public Product() {
}
}
@RequiredArgsConstructor
public class product {
private final Integer id;
private String name;
}
(註解生效原始碼) 效果同上,使用註解後可以看到只有帶 final 的屬性可以被帶入建立
public class product {
private final Integer id;
private String name;
public Product(Integer id) {
this.id = id;
}
}
**補充如果所有的屬性都沒有用 final 修飾的話,那就會生成一個沒有參數的起始子,等同 @NoArgsConstructor
可以產生 equals(Object other)
和 hashcode()
方法
@EqualsAndHashCode
public class Product {
private int id;
private String name;
private int price;
}
(註解生效原始碼) 效果同上,可以看到這兩個方法會 Override 原本 equals(0 和 hashcode()
public class Product {
private int id;
private String name;
private int price;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Product product = (Product) o;
return id == product.id && price == product.price && Objects.equals(name, product.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name, price);
}
}
舉例來說如果比較兩個物件,內部屬性相同
public static void main(String[] args) {
SpringApplication.run(MybatisDemoApplication.class, args);
Product product = Product.builder()
.id(1)
.name("book")
.price(100)
.build();
Product product1 = Product.builder()
.id(1)
.name("book")
.price(100)
.build();
// 判斷物件是否相等
System.out.println(product.equals(product1));
System.out.println(product.hashCode() == product1.hashCode());
}
預設的狀況會是兩個都是 False,因為只要新產生一個物件預設就是會有不同的記憶體位置,所以 reference 不同導致這兩個比較都 False,但是我們透過註解改寫上面兩個方法可以根據內部屬性的值是否都相等來判斷這兩個物件是否相等,hashcode 也會將內部的屬性值帶入去比較,就會得到兩個都是 True
等於同時加了以下注解
使用上可以讓 code 很簡潔,但須要注意這個註解實做哪些方法,才不會不知道為什麼有些東西不是如你所想的在運作,這註解也會導致一些部分的問題,像是有物件繼承時,@EqualsAndHashCode 這註解預設是不考慮父類別的屬性,可能就會導致你物件比較時會出錯。詳細可以閱讀參考資料 [4]。
等於同時加了以下注解,通常用來宣告給只讀取資料的物件使用,不提供任何 Setter
可以讓你使用特殊的流式語法來創建物件,簡化物件的創建過程。用了建造者模式(Builder Pattern),使得創建物件時更具靈活性和可讀性。
@Builder
public class Product {
private int id;
private String name;
private int price;
}
流式寫法,可讀性提高,也可以選擇性創建屬性提高靈活性,例如你可以只帶入 name , price 不帶 id 創建。
Product product = Product.builder()
.id(1)
.name("book")
.price(100)
.build();
不過使用這個通常還是會搭配 @Setter 因為有許多時候還是會操作物件去進行 set,所以通常Builder 會配合 @Data 一起使用。
自動產生 Log 的物件可以提供當前物件內使用,除了 @Slf4j 之外,lombok 也提供其他日誌框架,像是 @Log、@Log4j…等
註解使用後就可以直接使用 Slf4j相關的方法
@Slf4j
public class LogDemo {
public static void main(String... args) {
log.info("hello");
}
}
(原始定義方法)未使用需自行建立 Slf4j 物件
public class LogDemo {
private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogDemo.class.getName());
public static void main(String... args) {
log.info("hello");
}
}
其實在進一步認識了解之後,發現這個套件其實有蠻多討論針對是否要引用,甚至有許多團隊開發會不建議使用,其中我也是了解了一下這些部分,工作開發上我有碰過有使用也有碰過沒有使用,自己是開發個人小專案基本會使用,但多人開發上其實團隊內需要好好討論是否使用及一些規範需要訂出來,畢竟有許多缺點都是多人協作下會有問題,下面總結一些優缺點:
優點:
缺點:
Ref:
相關文章也會同步更新我的部落格,有興趣也可以在裡面找其他的技術分享跟資訊。