ホームページ  >  記事  >  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とマークされています。
  • すべてのフィールドはプライベートかつ最終的なものであるため、初期化後に変更することはできません。
  • フィールド値にアクセスするために提供されるのはゲッター メソッドのみです。

このアプローチはうまく機能しますが、コンストラクター、ゲッター、および場合によっては、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 アノテーションを使用してコンストラクターとゲッターを自動的に生成します。

  • @AllArgsConstructor は、すべてのフィールドをパラメータとして持つコンストラクターを生成します。
  • @Getter は各フィールドのゲッター メソッドを生成します。

@Value を使用してさらに簡素化する

Lombok の @Value アノテーションは、複数の機能を組み合わせて不変クラスを作成する、より強力な代替手段です。

import lombok.Value;

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

@Value を使用すると、ロンボク島は自動的に次のようになります:

  • クラスを最終決定します。
  • デフォルトでは、すべてのフィールドがプライベートかつ最終的なものになります。
  • すべての引数のコンストラクターを生成します。
  • すべてのフィールドのゲッターを生成します。
  • 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 クラスのロンボク化解除バージョン (つまり、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.unmodifiableList や List.of() などの不変バージョンを使用することを検討してください。
  • 複雑なオブジェクト: クラス フィールドがそれ自体が変更可能な複雑なオブジェクトである場合、クラスの不変性が損なわれます。すべてのフィールドがプリミティブな不変オブジェクトであるか、突然変異を防ぐために適切にカプセル化されていることを確認してください。

パフォーマンスに関する考慮事項

不変性には大きな利点がありますが、特に頻繁な更新を伴うシナリオでは、パフォーマンスへの影響を考慮することが重要です。

  • メモリ使用量: 変更が必要になるたびに新しいインスタンスを作成すると、メモリ使用量が増加する可能性があります。ただし、スレッドの安全性と複雑さの軽減という利点を考えると、このトレードオフには価値があることがよくあります。
  • ガベージ コレクション: 複数の存続期間の短いオブジェクトを作成すると、ガベージ コレクターにさらなる負荷がかかる可能性があります。アプリケーションのメモリ管理がそのようなシナリオに合わせて最適化されていることを確認してください。

結論

Lombok の @Value および @With アノテーションは、Java で不変クラスを作成するための強力かつ簡潔な方法を提供し、定型コードの必要性を排除し、コードをより読みやすく、保守しやすくします。これらのアノテーションを活用すると、クラス設計の仕組みではなく、アプリケーションのロジックに集中できます。

以上がJava コードを変換する: Lombok を使用してわずか数分で不変性の力を解き放ちます!の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。