首页 >Java >java教程 >转变您的 Java 代码:利用 Lombok 在短短几分钟内释放不变性的力量!

转变您的 Java 代码:利用 Lombok 在短短几分钟内释放不变性的力量!

WBOY
WBOY原创
2024-08-26 06:35:31818浏览

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