【问题标题】:Update an immutable object with Lombok in Java?在 Java 中使用 Lombok 更新不可变对象?
【发布时间】:2021-12-09 20:32:45
【问题描述】:

我有一个域类 Person 用 Lombok @Value 注释,因此将其标记为不可变,有 3 个字段。

在我的服务层中,我正在调用存储库以检查此人是否存在。

如果确实存在,我需要从数据库中获取Person 对象并更新money 字段。

由于它是不可变的,因此无法做到这一点。我正在阅读一些文章,发现这可以使用构建器模式来完成。

我可能需要在我的Person 类中创建一个updatePerson(),但不知道该怎么做。还是我需要做其他事情?

Person.java:

@Value
@Builder
public class Person {

    private final UUID id;
    private final String job;
    private final BigDecimal money;
    
}

我正在使用 Java 15。

【问题讨论】:

  • 听起来像money 不应该是final(所以可以更新)。将@Value 更改为@Data 应该为money 创建setter 和getter,并且只为仍然为final 的其他属性创建一个getter。
  • 我无法使用数据。这只需要是不可变的。

标签: java immutability lombok


【解决方案1】:

您还可以使用 lombok 的另一个功能,它不需要您使用构建器。它被称为@With,使用此注解将创建不可变的设置器,这意味着设置器返回一个新对象,该对象具有旧对象的属性,但您要更改的属性除外。

@Value
public class Person {
    /* You don't need to write final if you are using @Value. Lombok will make the variables final for you. 
    In theory you do not even need to write private, 
    because Lombok makes variables private by default instead of package private.*/
    private UUID id;
    private String job;
    @With 
    private BigDecimal money;
}

Person newPerson = person.withMoney(new Big decimal("10"));

一般来说,我不确定使对象不可变是否真的是一个好主意。除了 UUID 之外的每个变量似乎都可能在未来发生变化。

【讨论】:

  • 但是我将如何使用它呢?你能分享一下用法吗?喜欢这里适合我的情况的代码 sn-p 吗?
  • 很抱歉,我刚刚意识到我错过了那部分并在下面添加了它。
  • 这是我需要的。非常感谢!
【解决方案2】:

使用Lombok:

@Value
@Builder(toBuilder = true)
public class Person {

    private final UUID id;
    private final String job;
    private final BigDecimal money;
}

personObjectFromDatabase.toBuilder().setMoney(...).build()

或

在这种情况下,您可以使用Builder 模式:

public class Person {

    private final UUID id;
    private final String job;
    private final BigDecimal money;
    
    public static class PersonBuilder { 
            private UUID id;
            private String job;
            private BigDecimal money;

            public PersonBuilder(Person defaultPerson){ 
                this.id = defaultPerson.getId();
                this.job = defaultPerson.getJob();
                this.money = defaultPerson.getMoney();
            }
            public PersonBuilder withId(UUID id) {
                this.id = UUID;
                return this;
            }
            public PersonBuilder withJob(String job) {
                this.job = job;
                return this;
            }
            public PersonBuilder withMoney(BigDecimal money) {
                this.money = money;
                return this;
            }
            public Person build() {
                return new Person(id, job, money);
            }
     }
}

像下面这样使用这个构建器:

Person person = new Person.PersonBuilder(personObjectFromDatabase)
    .withMoney(...)
    .build();

或

你可以只创建一个copyWith() 方法:

public class Person {
    ...
    public Person copyWith(BigDecimal money) {
        return new Person(this.id, this.job, money);
    }
}

【讨论】:

【解决方案3】:

类是不可变的; 您永远无法更改该类实例的值。

相反, 您必须创建该类的新实例。

不要写生成器; 你已经在使用 Lombok, 只需使用 @Builder 注释,Lombok 将为您创建一个构建器。

编辑:您正在使用构建器注释。 您正在寻找的解决方案似乎是这样的:

你必须创建一个新的类实例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-13
    • 1970-01-01
    • 2019-09-24
    • 2014-08-24
    • 2019-11-12
    • 2017-03-30
    • 2018-07-16
    • 2021-09-18
    相关资源
    最近更新 更多