gpt4 book ai didi

java - 将类转换为记录时的兼容性问题

转载 作者:行者123 更新时间:2023-12-01 10:22:03 25 4
gpt4 key购买 nike

我一直在使用以下名为City的类

@ToString
@AllArgsConstructor
public class City {
Integer id;
String name;
}

并尝试将其转换为名为 recordCityRecord
record CityRecord(Integer id, String name) {} // much cleaner!

但是转向这种表示形式,我们的单元测试之一开始失败。这些测试在内部处理从JSON文件读取并映射到对象的城市列表,进一步将城市分组到 Map下进行计数。简化为:
List<City> cities = List.of(
new City(1, "one"),
new City(2, "two"),
new City(3, "three"),
new City(2, "two"));
Map<City, Long> cityListMap = cities.stream()
.collect(Collectors.groupingBy(Function.identity(),
Collectors.counting()));

上面的代码断言为true,其中包含4个键,每个键占其出现次数的1。对于记录表示形式,结果 Map中的键不超过3个。是什么原因造成的,解决该问题的方法应该是什么?

最佳答案

原因
观察到的行为背后的原因如java.lang.Record中所述

For all record classes, the following invariant must hold: if a recordR's components are c1, c2, ... cn, then if a record instance is copiedas follows:

 R copy = new R(r.c1(), r.c2(), ..., r.cn());   then it must be the case that r.equals(copy).

简而言之,您的 CityRecord类现在具有 equals(和哈希码)实现,该实现将两个属性进行比较,并确保它们是否相等,由这些组成部分组成的记录也相等。评估的结果是,具有相同属性的两个记录对象将被分组在一起。
因此,推断/断言应该存在三个这样的 key 的结果是正确的,其中一个 id=2, name="two"计数了两次。
立即补救
一个直接的临时解决方案是在您的记录表示形式中也创建一个自定义(有缺陷的原因,稍后说明)。看起来像:
record CityRecord(Integer id, String name) {

// WARNING, BROKEN CODE
// Does not adhere to contract of `Record::equals`
@Override
public boolean equals(Object o) {
return this == o;
}

@Override
public int hashCode() {
return System.identityHashCode(this);
}
}
现在,就像在使用现有 equals类时那样,将在两个对象之间进行比较,您的测试将正常进行。但是在使用任何此类补救措施之前,您必须注意以下注意事项。
警告
正如 JEP-359所读,记录更像是“数据载体”,并且在选择迁移现有的类时,您必须意识到记录自动获取的标准成员。
计划进行迁移必须了解当前实现的完整细节,例如在按 City分组时引用的示例中,没有理由将两个具有相同 Cityid数据的城市以不同的方式列出。它们应该相等,所有重复两次后应该是相同的数据,因此计数正确。
在这种情况下,可以通过覆盖 name实现以比较各个属性的方式,纠正您现有的实现(如果表示数据模型),使其与 record相匹配,这也是上述直接补救措施相互矛盾的地方,应避免使用。

关于java - 将类转换为记录时的兼容性问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60796961/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com