我正在使用具有集合属性的不可变对象。像这样的东西:
@Value
@Builder(toBuilder = true)
class Person {
String name;
@Singular
Set<String> skills;
}
当我从现有的 Person 创建一个新实例但具有更新的技能时,集合似乎没有更新。
Person jonh = Person.builder()
.name("John")
.build();
System.out.println(jonh);
Person johnUpgraded = jonh.toBuilder()
.skill("Java")
.skill("Spring")
.build();
System.out.println(johnUpgraded);
Person johnDowngraded = johnUpgraded.toBuilder()
.skills(Collections.emptySet())
.build();
System.out.println(johnDowngraded);
它打印:
Person(name=John, skills=[])
Person(name=John, skills=[Java, Spring])
Person(name=John, skills=[Java, Spring])
是否可以创建人的副本并设置其他技能?
非常感谢您考虑我的要求!
是否可以创建人的副本并设置其他技能?
您可以先调用
clearSkills()
来完全重置该集合的内容。否则所有值保持不变;与@Singular
所有setter方法都像“加法器”一样。
首先,您的
.skills(Collections.emptySet())
方法只是在现有集合之上添加空集合。
如果你想清除它,只需使用 `clear() 方法:
//to make it work, add @Getter annotation on top of your Person class
johnUpgraded.getSkills().clear();
是否可以创建人的副本...
According to this answer
toBuilder()
method doesn't do deep copy.所以jonh
,johnUpgraded
和johnDowngraded
是同一个对象。
要复制您的对象,您必须再次使用
Person.builder()
,如下所示:
Person jonh = Person.builder()
.name("John")
.build();
Person johnUpgraded = Person.builder()
.name(jonh.getName())
.skill("Java")
.skill("Spring")
.build();
更新:
要克隆你的集合,根据前一个集合创建另一个。
.skill(new HashSet<>(jonh.getSkills()));
您可以使用
@With
-er 干净地完成此操作。这个注解生成一个 with
方法,类似于 setter,但它会返回对象的一个新实例。在我看来,这是实现不可变对象的方法:
import lombok.With;
@Value
@Builder
static class Person {
String name;
@With
@Singular
Set<String> skills;
}
@Test
void test() {
Person jonh = Person.builder()
.name("John")
.build();
System.out.println(jonh);
Person johnUpgraded = jonh.withSkills(Set.of(
"Java",
"Spring"
));
System.out.println(johnUpgraded);
}