记录属性的默认值

Ant*_*gos 19 java record

如果我有一个包含 2 个属性的 Java 记录,并且我想为应该使用的属性定义默认值,而不是 null。我可以重写吸气剂:

\n
public record MyRecord(Set<String> strings, Boolean required) {\n\n    @Override\n    public Boolean required() {\n        return Objects.requireNonNullElse(this.required, Boolean.TRUE);\n    }\n\n    @Override\n    public Set<String> strings() {\n        return Objects.requireNonNullElse(this.strings, Set.of());\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

\xe2\x80\xa6or 我可以通过覆盖默认构造函数来实现同样的效果:

\n
public record MyRecord(Set<String> strings, Boolean required) {\n\n    public MyRecord(Set<String> strings, Boolean required) {\n        this.strings = Objects.requireNonNullElse(strings, Set.of());\n        this.required = Objects.requireNonNullElse(required, Boolean.TRUE);\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

这两个看起来都有点冗长,有没有更简洁的方法来为记录属性分配默认值?

\n

Hol*_*ger 19

像第一个变体一样重写访问器方法违反了您可以使用访问器方法和规范构造函数创建相等对象的期望。从文档中

\n
\n

对于所有记录类,必须满足以下不变量:如果记录 R 的组件是c1, c2, ... cn,则如果按如下方式复制记录实例:

\n
    R copy = new R(r.c1(), r.c2(), ..., r.cn());\n
Run Code Online (Sandbox Code Playgroud)\n

那么情况一定是这样的r.equals(copy)

\n
\n

但是使用重写的访问器方法,以下断言将失败:

\n
    R copy = new R(r.c1(), r.c2(), ..., r.cn());\n
Run Code Online (Sandbox Code Playgroud)\n

因为内部字段包含不同的数据。

\n

因此,修复输入数据的唯一正确方法是在构建过程中,例如

\n
MyRecord r1 = new MyRecord(null, null), r2 = new MyRecord(r1.strings(), r1.required());\nassert r1.equals(r2);\n
Run Code Online (Sandbox Code Playgroud)\n

null但是,您根本不应该\xe2\x80\x99 执行此处理。集合永远不应该是null,并且用于Boolean构造函数意味着Boolean通常具有记录组件类型,即也由访问器方法返回。而用写new MyRecord(null, null)代替new MyRecord(Set.of(), true)\xe2\x80\x99甚至不会节省很多打字时间。

\n

如果你想支持默认值,你应该重载构造函数,例如

\n
public record MyRecord(Set<String> strings, Boolean required) {\n    public MyRecord {\n        if(strings == null) strings = Set.of();\n        if(required == null) required = true;\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

所以你可以使用new MyRecord()默认值。或者您认为记录是不可变的,因此不需要构建默认值的多个实例\xe2\x80\x99

\n
public record MyRecord(Set<String> strings, boolean required) {\n    public MyRecord {\n        strings = Set.copyOf(strings); // enforce non-null immutable set\n    }\n    public MyRecord() {\n        this(Set.of(), true);\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

MyRecord.DEFAULT并在需要默认值时使用。当然,如果需要的话,您仍然可以为只有一个参数应具有默认值的情况提供重载构造函数。

\n

  • 这正是 Spring 内部所做的。由于它们控制实例(bean)的创建,因此它们还允许在记录属性上使用“@DefaultValue”注释。 (3认同)