首頁  >  文章  >  Java  >  轉變您的 Java 程式碼:利用 Lombok 在短短幾分鐘內釋放不變性的力量!

轉變您的 Java 程式碼:利用 Lombok 在短短幾分鐘內釋放不變性的力量!

WBOY
WBOY原創
2024-08-26 06:35:31779瀏覽

Transform Your Java Code: Unlock the Power of Immutability with Lombok in Just Minutes!

為什麼使用不可變類別?

不可變類別是有益的,因為它們本質上是線程安全的,易於推理,並且可以防止物件狀態的意外更改。不可變物件的狀態在創建後無法修改,這使其成為一種有價值的設計模式,尤其是在多執行緒環境中。

創建不可變類別的傳統方法

考慮以下 Employee 類別:

final class Employee {
    private final long id;
    private final String name;
    private final double salary;

    public Employee(long id, String name, double salary) {
        this.id = id;
        this.name = name;
        this.salary = salary;
    }

    public long getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public double getSalary() {
        return salary;
    }
}

採用這種傳統方法:

  • 該類別被標記為 Final 以防止子類化。
  • 所有欄位都是私有且最終的,確保它們在初始化後無法變更。
  • 僅提供 getter 方法來存取欄位值。

雖然這種方法效果很好,但它涉及為建構子、getter 編寫樣板程式碼,有時還需要為 equals、hashCode 和 toString 方法編寫樣板程式碼。

使用 Lombok 消除樣板文件

Lombok 可以大幅減少您需要編寫的程式碼量。以下是如何使用 Lombok 實現相同功能的方法:

import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor
@Getter
final class Employee {
    private final long id;
    private final String name;
    private final double salary;
}

此版本使用Lombok註解自動產生建構子和getter:

  • @AllArgsConstructor 產生一個以所有欄位作為參數的建構子。
  • @Getter 為每個欄位產生 getter 方法。

使用 @Value 進一步簡化

Lombok 的 @Value 註解是一個更強大的替代方案,它結合了多個功能來創建不可變的類別:

import lombok.Value;

@Value
class Employee {
    long id;
    String name;
    double salary;
}

使用@Value,Lombok會自動:

  • 使課程進入決賽。
  • 預設將所有欄位設為私有和最終。
  • 產生一個全參數建構子。
  • 為所有欄位產生 getter。
  • 實作 equals、hashCode 和 toString 方法。

這將您的類別定義簡化為僅包含字段,並自動產生所有必要的程式碼。

使用@With處理欄位更新

不可變物件不允許修改其狀態。但是,在某些情況下,您可能需要建立物件的修改副本,例如更新員工的薪資。如果沒有 Lombok,這可能看起來像:

@Value
class Employee {
    long id;
    String name;
    double salary;
}

class Main {
    public static void main(String... args) {
        var emp = new Employee(1L, "Aman", 10_000.0);
        emp = updateSalary(emp, 12_0000.0);
    }

    public Employee updateSalary(Employee emp, long newSalary) {
        return new Employee(emp.getId(), emp.getName(), newSalary);
    }
}

這很簡單但很乏味,特別是在處理具有許多欄位的類別時。

Lombok 的 @With 註解簡化了這一點:

import lombok.Value;
import lombok.With;

@Value
class Employee {
    long id;
    String name;
    @With double salary;
}

class Main {
    public static void main(String... args) {
        var emp = new Employee(1L, "Aman", 10_000.0);
        emp = updateSalary(emp, 12_0000.0);
    }

    public Employee updateSalary(Employee emp, double newSalary) {
        return emp.withSalary(newSalary);
    }
}

@With 註解產生一個方法,該方法傳回類別的新實例,並更新指定字段,其餘部分保持不變。

最終的解龍目版本

我們的 Employee 類別的 de-lomboked 版本(即 Lombok 在背景產生的內容)將如下所示:

final
class Employee {
    private final long id;
    private final String name;
    private final double salary;

    public Employee(long id, String name, double salary) {
        this.id = id;
        this.name = name;
        this.salary = salary;
    }

    public Employee withSalary(double salary) {
        return this.salary == salary ? this : new Employee(this.id, this.name, salary);
    }

    public long getId() {
        return this.id;
    }

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

    public double getSalary() {
        return this.salary;
    }

    @Override
    public boolean equals(final Object o) {
        if (o == this) return true;
        if (!(o instanceof Employee)) return false;
        final Employee other = (Employee) o;
        if (this.getId() != other.getId()) return false;
        final Object this$name = this.getName();
        final Object other$name = other.getName();
        if (this$name == null ? other$name != null : !this$name.equals(other$name)) return false;
        return Double.compare(this.getSalary(), other.getSalary()) == 0;
    }

    @Override
    public int hashCode() {
        final int PRIME = 59;
        int result = 1;
        final long $id = this.getId();
        result = result * PRIME + (int) ($id >>> 32 ^ $id);
        final Object $name = this.getName();
        result = result * PRIME + ($name == null ? 43 : $name.hashCode());
        final long $salary = Double.doubleToLongBits(this.getSalary());
        result = result * PRIME + (int) ($salary >>> 32 ^ $salary);
        return result;
    }

    @Override
    public String toString() {
        return "Employee(id=" + this.getId() + ", name=" + this.getName() + ", salary=" + this.getSalary() + ")";
    }
}

使用 Lombok 實現不變性時的常見陷阱

雖然 Lombok 簡化了不可變類的創建,但請務必注意一些潛在的陷阱:

  • 可變集合:如果您的類別包含可變集合(如 List 或 Map),Lombok 的 @Value 註解將無法保護您免受這些集合的修改。考慮使用不可變版本,如 Collections.unmodifyingList 或 List.of() 進行初始化。
  • 複雜物件:如果您的類別欄位是本身可變的複雜對象,則類別的不變性會受到損害。確保所有欄位都是原始的、不可變的對象,或正確封裝以防止突變。

性能考慮因素

雖然不變性提供了顯著的好處,但考慮效能影響也很重要,特別是在涉及頻繁更新的場景中:

  • 記憶體使用量: 每次需要更改時建立新實例可能會導致更高的記憶體使用量。然而,為了線程安全和降低複雜性的好處,這種權衡通常是值得的。
  • 垃圾收集: 建立多個短期物件會對垃圾收集器造成額外的壓力。確保您的應用程式的記憶體管理針對此類場景進行了最佳化。

結論

Lombok 的@Value 和@With 註解提供了一種強大而簡潔的方法來在Java 中創建不可變類,消除了對樣板程式碼的需求,並使您的程式碼更具可讀性和可維護性。透過利用這些註釋,您可以專注於應用程式的邏輯,而不是類別設計的機制。

以上是轉變您的 Java 程式碼:利用 Lombok 在短短幾分鐘內釋放不變性的力量!的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn