如果我有一个包含 2 个属性的 Java 记录,并且我想为应该使用的属性定义默认值而不是 null。我可以重写吸气剂
public record MyRecord(
Set<String> strings,
Boolean required) {
@Override
public Boolean required() {
return Objects.requireNonNullElse(this.required, Boolean.TRUE);
}
@Override
public Set<String> strings() {
return Objects.requireNonNullElse(this.strings, Set.of());
}
}
或者我可以通过覆盖默认构造函数来实现同样的事情
public record MyRecord(
Set<String> strings,
Boolean required) {
public MyRecord(Set<String> strings, Boolean required) {
this.strings = Objects.requireNonNullElse(strings, Set.of());
this.required = Objects.requireNonNullElse(required, Boolean.TRUE);
}
}
这两个看起来都有点冗长,有没有更简洁的方法来为记录属性分配默认值?
像第一个变体一样重写访问器方法违反了您可以使用访问器方法和规范构造函数创建相等对象的期望。 来自文档
对于所有记录类,必须满足以下不变量:如果记录 R 的组件是
,则如果按如下方式复制记录实例:c1, c2, ... cn
R copy = new R(r.c1(), r.c2(), ..., r.cn());
那么一定是这样的
.r.equals(copy)
但是使用重写的访问器方法,以下断言将失败:
MyRecord r1 = new MyRecord(null, null), r2 = new MyRecord(r1.strings(), r1.required());
assert r1.equals(r2);
因为内部字段包含不同的数据。
因此,修复输入数据的唯一正确方法是在构建过程中,例如
public record MyRecord(Set<String> strings, Boolean required) {
public MyRecord {
if(strings == null) strings = Set.of();
if(required == null) required = true;
}
}
但是,您根本不应该进行这种
null
处理。集合永远不应该是 null
并且使用 Boolean
作为构造函数意味着通常具有 Boolean
记录组件类型,即也由访问器方法返回。而且写 new MyRecord(null, null)
而不是 new MyRecord(Set.of(), true)
甚至不能节省太多打字时间。
如果你想支持默认值,你应该重载构造函数,例如
public record MyRecord(Set<String> strings, boolean required) {
public MyRecord {
strings = Set.copyOf(strings); // enforce non-null immutable set
}
public MyRecord() {
this(Set.of(), true);
}
}
因此您可以使用
new MyRecord()
作为默认值。或者您认为记录是不可变的,因此没有必要构建多个默认实例
public record MyRecord(Set<String> strings, boolean required) {
public static final MyRecord DEFAULT = new MyRecord(Set.of(), true);
public MyRecord {
strings = Set.copyOf(strings); // enforce non-null immutable set
}
}
并在需要默认值时使用
MyRecord.DEFAULT
。当然,如果需要的话,您仍然可以为只有一个参数应该有默认值的情况提供重载构造函数。