[英]Creating immutable Records having mutable fields
我想创建一个不可变的记录,它有 2 个可变字段 Date 和一个 HashMap
public record ImmutableRecord(String name, LocalDate admissionDate, Date dateOfBirth, Map<String, Integer> metaData) {
public ImmutableRecord{
// Date is a mutable field
dateOfBirth = new Date(dateOfBirth.getTime());
// HashMap is a mutable field
Map<String, Integer> tempMap = new HashMap<>();
for(Map.Entry<String, Integer> entry: metaData.entrySet()){
tempMap.put(entry.getKey(), entry.getValue());
}
metaData = tempMap;
//Can I use following instead of above for deep copying the map?
metaData = Map.copyOf(metaData);
}
}
使用 forEach 深度克隆每个字段或使用 Map.copyOf 以下哪种方法是正确的
首先,在设计上,一般来说复制数据的责任应该落在实例化记录的调用方法上。 构造函数通常不应该进行这种复制。
让我们更改此记录的名称,因为“ImmutableRecord”是多余的,并且无法反映您的问题域。 鉴于录取日期字段,显然您打算代表学生。 所以你的整个 class 定义可能是:
public record Student ( String name, LocalDate admitted, LocalDate dateOfBirth, Map<String, Integer> metaData ) {}
The modern and immutable LocalDate
class should always be used instead of the mutable legacy class java.sql.Date
class.
调用方法应该进行复制,如下所示。
关于您尝试克隆 map:
Map<String, Integer> tempMap = new HashMap<>();
for(Map.Entry<String, Integer> entry: metaData.entrySet()){
tempMap.put(entry.getKey(), entry.getValue());
}
这种复制不是深度克隆。 您没有复制密钥的内容。 您也没有复制值的内容。 您确实创建了另一个Map
object。 但是旧的 map 和新的 map 都有包含对相同键和值对象的引用的条目。
您的复制实际上与仅将旧 map 传递给新 map 的构造函数相同。 新旧 map 都有指向相同键对象和相同值对象的条目。
Map < String , Integer > metaData = new HashMap <> ( oldMetaData ) ;
Your copying is nearly the same as Map.copyOf( oldMap )
except that copyOf
produces an unmodifiable map of some unspecified class implementing Map
rather than a modifiable HashMap
. 但就像您上面的代码一样,旧映射和新映射都指向相同的键对象和相同的值对象。
所以调用代码看起来像这样:
Student someStudent = new Student( "Alice" , … ) ;
…
Student twinStudent =
new Student(
"Bob" ,
LocalDate.of( 2021, Month.MARCH, 23 ),
someStudent.dateOfBirth,
Map.copyOf( someStudent.metaData )
)
;
记录功能的目的是简明地定义一个 class,其主要目的是透明和不可变地传递数据。 所以理想情况下,记录应该包含不可变的内容。 这是另一个更喜欢Map.copyOf
而不是新的HashMap
的原因。
正如所评论的,另一个更喜欢Map.copyOf
的原因是,如果传递的 map 已经不可修改,则直接返回传递的 map。 使用较少的 memory,使用较少的 CPU。
正如所评论的,使用Map.copyOf
的一个可能限制是,在 map 参考中,任何键或任何值中都不允许出现空值。 Map.copyOf
是一个“无空区”,这是我自己新创造的术语。
如果您的方案中可以容忍空值,则替代方案是Collections.unmodifiableMap
。 并且,对于防御性编程,复制 map 被Collections.unmodifiableMap
包裹。
metaData = Collections.unmodifiableMap( new HashMap<>( oldMetaData ) ) ;
最好将设计决策视为二元的......即,它是不可变的吗?
在你的情况下,你有一些可变的东西。 在这种情况下,只需使用 Lombok @Data
来构建它。
此外,您还可以:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.