当前位置: 首页 > 面试题库 >

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

洪凯定
2023-03-14
问题内容

我一直在与以下名为 City

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

并试图将其转换为一个record名为CityRecord作为

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。使用记录表示法,结果中的键不超过3个Map。是什么原因造成的,解决该问题的方法应该是什么?


问题答案:

原因

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

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

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

that r.equals(copy).

简而言之,您的CityRecord类现在具有一个equals(和哈希码)实现,用于比较这两个属性,并确保它们相等时,由这些组件组成的记录也相等。评估的结果是,具有相同属性的两个记录对象将被分组在一起。

因此,推断/断言应该存在三个这样的密钥而一个已经id=2, name="two"计数了两次的结果将是正确的。

立即补救

一个直接的临时解决方案equals在您的记录表示形式中创建一个自定义(有缺陷的原因,稍后说明)。看起来像:

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);
    }
}

现在,就像使用现有City类一样,将在两个对象之间进行比较,您的测试将正常进行。但是在使用任何此类补救措施之前,您必须注意以下注意事项。

警告

正如JEP-359所读,记录更像是“数据载体”,并且在选择迁移现有的类时,您必须意识到
记录自动获取标准成员

计划迁移时,必须了解当前实施的完整细节,例如在按分组时引用的示例中City,没有理由将两个城市相同idname 数据
列出的顺序不同。它们应该相等,所有重复 两次 后应该是 相同的数据 ,因此计数正确。 __

在这种情况下,可以record通过覆盖equals实现以比较各个属性的方式来纠正您现有的实现(如果表示数据模型)以与之匹配,这是上述直接补救措施相互矛盾的地方,应避免使用。



 类似资料:
  • 但是当我们转向这样的表示时,我们的一个单元测试开始失败。测试在内部处理从JSON文件读取并映射到对象的城市列表,进一步计算城市数,同时将它们分组到中。简化为: 上面的代码断言为true,以包含4个键,每个键占其出现次数的1。使用记录表示法,生成的中的键不超过3个。是什么造成了这种情况?应该采取什么办法来解决这种情况?

  • 我试图编译一个从SourceForge得到的仍在开发中的项目。这是它的地址:。https://sourceforge.net/p/groove/code/5475/tree/groove/trunk/我知道这个项目经过了很好的验证,它没有任何错误,但是当我要编译它的时候,我遇到了这个编译错误: 错误在这个文件的第370行:https://sourceforge.net/p/groove/code/

  • Avro SpecificRecord(即生成的java类)是否与模式演化兼容?一、 e.如果我有一个Avro消息源(在我的例子中是Kafka),并且我想将这些消息反序列化为特定的记录,那么这样做是否安全? 我所看到的: 将字段添加到架构的末尾效果很好-可以将ok反序列化为specificrecord 在中间添加字段不会破坏现有客户机 即使消息兼容,这也是一个问题。 如果我能找到新的模式(例如使用

  • 我试图通过在一个单独的线程上进行工作并返回所需的对象来更改JavaFX中的GUI。然而,在完成工作和任务之后。setOnSucceeded()在尝试检索创建的对象时被触发,并出现错误“不兼容类型:对象无法转换为VideoScrollPane类型”。 我认为这与原始类型有关,因为这是在听众中发生的,但环顾四周后,我找不到我想要的建议。 任何可以散发的光芒都将不胜感激。

  • 问题内容: 一般来说,对于Java和编程,我是一个新手。我正在尝试创建一个简单的程序,您可以在其中猜测我的年龄,如果您是对的,它将说“正确”,如果您错了,它将说“错”。 这是我的代码: 我收到错误消息“不兼容的类型:void无法转换为int”,但代码中没有void类?我知道我的代码可能很糟糕,但是如果你们能为我指出正确的方向,那就太好了。谢谢。 问题答案: 您的程序不必返回in 。相反,您可以将其

  • 我试图在if语句中调用一个方法,但我总是得到以下错误。 不兼容的类型:java.lang.String不能转换为boolean