iT邦幫忙

2022 iThome 鐵人賽

DAY 23
0

身為 Java 開發者的你有沒有過一種感覺,感覺 Java 語法有點囉嗦?滿山滿谷的 getter、setter 大同小異卻又不能沒有它們,雖然 IDE 能幫你快速產出這類程式碼,但它們還是在,臃腫的你我心煩。

Lombok 正是為此存在,它是一個 Java 函式庫,通過使用其提供的註解 (Annotation) 讓我們省略一些常用、重複性高的程式碼。Lombok 是種語法糖,並沒有改變 Java 的本質,它只是告訴 IDE:「別這麼死板,就當那些不存在的 code 已經寫過了。」,然後 Lombok 會在編譯時幫你補上。

安裝

加入 Maven 依賴。

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.22</version>
    <scope>provided</scope>
</dependency>

安裝 Lombok plugin 到 Eclipse,有兩種做法:

  • jar 檔

    Maven 下載好套件後,到 .m2 下的 Lombok 目錄下雙擊執行 lombok.jar 打開安裝程式。安裝程式會自動找到 Eclipse 的位置,只要照指示安裝就好。

    lombok.jar 也可以到 https://projectlombok.org/download 下載,檔案一樣。

  • Eclipse 內建 plugin installer

    打開 Eclipse 點 Help > Install New Software...Work with: 欄位輸入 https://projectlombok.org/p2,執行安裝。

用法

本文只介紹常用的幾個功能,想瞭解完整功能請到 https://projectlombok.org/features/

@Getter / @Setter

  • 標註在類別上,Lombok 會自動建立所有 field 的 getter/setter。
  • 標註在 field 上,Lombok 會自動建立單個 field 的 getter/setter。
  • 如果變數型態是 boolean,用 @Getter 會產生 is 開頭的方法,例如: isEnabled()
  • 產生的方法預設是 public,可以用 AccessLevel 修改成: PUBLICPROTECTEDPACKAGEPRIVATENONE

Java + Lombok

@Getter
@Setter(AccessLevel.PROTECTED)
public class Example {
    private String name;
    private boolean enabled;
}

Java

public class Example {
    private String name;
    private boolean enabled;

    public String getName() {
        return this.name;
    }

    protected void setName(final String name) {
        this.name = name;
    }

    public boolean isEnabled() {
        return this.enabled;
    }

    protected void setEnabled(final boolean enabled) {
        this.enabled = enabled;
    }
}

@ToString

  • 標註在類別上,Lombok 會自動實作 toString()
  • toString() 預設印出所有非 static 的 field。
  • 可用 @ToString.Exclude 排除不想印出的 field。
  • 可設定 @ToString(onlyExplicitlyIncluded = true) 改成預設不印出任何 field,然後用 @ToString.Include 加入想印出的 field。
  • 可設定 @ToString(callSuper = true),一併呼叫父類別的 toString() 印出。

Java + Lombok

@ToString
public class Example {
    private Integer age;
    private String name;
    @ToString.Exclude
    private boolean enabled;
}

Java

public class Example {
    private Integer age;
    private String name;
    private boolean enabled;

    @Override
    public String toString() {
        return "Example(age=" + this.age + ", name=" + this.name + ")";
    }
}

@EqualsAndHashCode

  • 標註在類別上,Lombok 會自動實作 equals(Object other)hashCode()
  • 預設比對所有非 statictransient 的 field。
  • 可用 @EqualsAndHashCode.Exclude 排除不想比對的 field。
  • 可設定 @EqualsAndHashCode(onlyExplicitlyIncluded = true) 改成預設不比對任何 field,然後用 @EqualsAndHashCode.Include 加入想比對的 field。
  • 如果該類別繼承自父類別,那父類別的 field 也應該要進行比對,但要注意 Lombok 不會自動建立父類別的 equalshashCode 。 可設定 @EqualsAndHashCode(callSuper = true) 一併呼叫父類別的 equalshashCode 進行比對。

Java + Lombok

@EqualsAndHashCode
public class Example {
    private Integer age;
    private String name;
    @EqualsAndHashCode.Exclude
    private boolean enabled;

    public String getName() {
        return this.name;
    }
}

Java

public class Example {
    private Integer age;
    private String name;
    private boolean enabled;

    public String getName() {
        return this.name;
    }

    @Override
    public boolean equals(final Object o) {
        if (o == this) return true;
        if (!(o instanceof Example)) return false;
        final Example other = (Example) o;
        if (!other.canEqual((Object) this)) return false;
        if (this.age == null ? other.age != null : !this.age.equals(other.age)) return false;
        if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false;
        return true;
    }

    protected boolean canEqual(final Object other) {
        return other instanceof Example;
    }

    @Override
    public int hashCode() {
        final int PRIME = 59;
        int result = 1;
        result = result * PRIME + (this.age == null ? 43 : this.age.hashCode());
        result = result * PRIME + (this.getName() == null ? 43 : this.getName().hashCode());
        return result;
    }
}

@NonNull

  • 標註 @NonNull 在 field 上,Lombok 會加入 null check 到由 Lombok 建立的相關方法或建構子。
  • 標註 @NonNull 在方法或建構子的參數上,Lombok 會建立 null check 到方法 / 建構子。
  • Null check 會插入在方法 / 建構子的 this()super() 之後,其它程式碼之前。
  • Null check 失敗時會拋出 NullPointerException

Java + Lombok

public class Example {
    private String name;

    public Example(@NonNull Person person) {
        super();
        this.name = person.getName();
    }
}

Java

public class Example {
    private String name;

    public Example(@NonNull Person person) {
        super();
        if (person == null) {
            throw new NullPointerException("person is marked non-null but is null");
        }
        this.name = person.getName();
    }
}

@NoArgsConstructor / @RequiredArgsConstructor / @AllArgsConstructor

  • 標註 @NoArgsConstructor 在類別上,Lombok 會建立沒有參數的建構子,要注意:
    • 很多函式庫都會用到物件的無參數建構子,所以最好要實作。當沒有實作任何建構子時編譯器會自動產生一個無參數建構子,但只要實作了任一建構子,編譯器就不會幫我們建立,所以用 Lombok 處理建構子時最好一律加上 @NoArgsConstructor)。
    • 當類別裡有宣告為 final 且沒預設值的 field 時 IDE 會報錯,如果你不想宣告預設值,可以用 @NoArgsConstructor(force = true),讓建構子把這些 field 設成 0 / false / null
  • 標註 @RequiredArgsConstructor 在類別上,Lombok 會建立參數為待處理 field 的建構子。待處理 field 是指沒預設值,且宣告為 final 或標註 @NonNull 的 field。
  • 標註 @AllArgsConstructor 在類別上,Lombok 會建立參數為所有 field 的建構子。

Java + Lombok

@NoArgsConstructor(force = true)
@RequiredArgsConstructor
@AllArgsConstructor
public class Example {
    private String name;
    private final boolean enabled;
}

Java

public class Example {
    private String name;
    private final boolean enabled;

    public Example() {
        this.enabled = false;
    }

    public Example(final boolean enabled) {
        this.enabled = enabled;
    }

    public Example(final String name, final boolean enabled) {
        this.name = name;
        this.enabled = enabled;
    }
}

@Data

  • 標註 @Data 在類別上,等於同時標註了:
    • @Getter
    • @Setter
    • @ToString
    • @EqualsAndHashCode
    • @RequiredArgsConstructor
  • @Data 內沒有包含 @NoArgsConstructor,再次提醒,最好加上。
  • @Data 內含的 annotation 都是預設值,如果想要改設定,請另外加上要改的標籤與參數。
  • 如果類別裡已經有和 Lombok 要建立的方法同名且參數數量相同的存在,則 Lombok 會跳過不處理。(這個規則在所有標籤都適用)

Java + Lombok

@Data
public class ExampleData {
    private String name;
    private final boolean enabled;
}

Java

public class Example {
    private String name;
    private final boolean enabled;

    public Example(final boolean enabled) {
        this.enabled = enabled;
    }

    public String getName() {
        return this.name;
    }

    public void setName(final String name) {
        this.name = name;
    }

    public boolean isEnabled() {
        return this.enabled;
    }

    @Override
    public boolean equals(final Object o) {
        if (o == this) return true;
        if (!(o instanceof Example)) return false;
        final Example other = (Example) o;
        if (!other.canEqual((Object) this)) return false;
        if (this.isEnabled() != other.isEnabled()) return false;
        if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false;
        return true;
    }
    
    protected boolean canEqual(final Object other) {
        return other instanceof Example;
    }

    @Override
    public int hashCode() {
        final int PRIME = 59;
        int result = 1;
        result = result * PRIME + (this.isEnabled() ? 79 : 97);
        result = result * PRIME + (this.getName() == null ? 43 : this.getName().hashCode());
        return result;
    }

    @Override
    public String toString() {
        return "Example(name=" + this.getName() + ", enabled=" + this.isEnabled() + ")";
    }
}

@Log

  • 標註 @Log 在類別上,Lombok 會建立一個 log 的 static final 常數。
  • Lombok 支援多種不同的 log 框架,每種都有對應的 annotataion,例如: @Log@Log4j2@Slf4j

Java + Lombok

@Log4j2
public class Example {

}

Java

public class Example {
    private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(Example.class);
}

Delombok

Delombok 是 Lombok 內建的工具,能把含 Lombok 的 Java 程式碼輸出成純 Java 程式碼,對於讓我們了解 Lombok 做了什麼很有幫助。

  • 輸出成檔案

    使用 CLI 對 .m2 下的 lombok.jar 執行以下指令:

    • {src} - 含 Lombok 的 Java 檔案目錄。

    • {src-delomboked} - 輸出純 Java 檔案目錄。

      java -jar lombok.jar delombok {src} -d {src-delomboked}
      
  • 輸出到 console

    使用 CLI 對 .m2 下的 lombok.jar 執行以下指令:

    • {MyJavaFile.java} - 含 Lombok 的 Java 檔案路徑。

      java -jar lombok.jar delombok -p {MyJavaFile.java}
      

上一篇
[Day22] Spring Cloud 與 GCS
下一篇
[Day24] 經濟部商業司Open API應用
系列文
Google商家大解密就靠網頁設計來加成30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言