标签: java-record

Java 14 记录和数组

鉴于以下代码:

public static void main(String[] args) {
    record Foo(int[] ints){}

    var ints = new int[]{1, 2};
    var foo = new Foo(ints);
    System.out.println(foo); // Foo[ints=[I@6433a2]
    System.out.println(new Foo(new int[]{1,2}).equals(new Foo(new int[]{1,2}))); // false
    System.out.println(new Foo(ints).equals(new Foo(ints))); //true
    System.out.println(foo.equals(foo)); // true
}
Run Code Online (Sandbox Code Playgroud)

显然,似乎使用了数组的toString,equals方法(而不是静态方法、Arrays::equalsArrays::deepEqualsArray::toString)。

所以我猜 Java 14 Records ( JEP 359 ) 不能很好地处理数组,必须使用 IDE 生成相应的方法(至少在 IntelliJ 中,默认情况下会生成“有用”的方法,即它们使用静态方法在Arrays)。

或者还有其他解决方案吗?

java arrays java-14 java-record

15
推荐指数
3
解决办法
1015
查看次数

使用新的 Record 类时无法反序列化

我想看看我是否可以用 Java 14 中的新 Record 类替换我现有的 Pojo。但无法这样做。得到以下错误:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException:无法构造实例com.a.a.Post(无创建者,如默认构造,存在):无法从对象值反序列化(无基于委托或属性的创建者)

我知道错误是说记录没有构造函数,但是从我所看到的记录类在后台处理它,并且相关的 getter 也在后台设置(不完全是 getter,而是 id() title() 等等没有 get 前缀)。是不是因为 Spring 还没有采用最新的 Java 14 记录?请指教。谢谢。

我在 Spring Boot 版本 2.2.6 中执行此操作并使用 Java 14。

以下使用通常的 POJO 工作。

邮政类

public class PostClass {
    private int userId;
    private int id;
    private String title;
    private String body;

    public int getUserId() {
        return userId;
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) { …
Run Code Online (Sandbox Code Playgroud)

java spring spring-boot java-14 java-record

13
推荐指数
2
解决办法
2556
查看次数

在 Java 记录中强制执行不可变集合?

Java 记录用于实现浅不可变的数据载体类型。如果构造函数接受可变类型,那么我们应该实现显式防御性复制以强制不变性。例如

record Data(Set<String> set) {
    public Data(Set<Thing> set) {
        this.set = Set.copyOf(set);
    }
}
Run Code Online (Sandbox Code Playgroud)

这有点烦人 - 我们必须

  1. 实现一个老式的 POJO 构造函数(复制字段)而不是使用规范的构造函数和
  2. 显式初始化每个字段只是为了处理可变字段的防御性副本。

理想情况下,我们想要表达的是以下内容:

record SomeRecord(ImmutableSet<Thing> set) {
}
Run Code Online (Sandbox Code Playgroud)

或者

record SomeRecord(Set<Thing> set) {
    public SomeRecord {
        if(set.isMutable()) throw new IllegalArgumentException(...);
    }
}
Run Code Online (Sandbox Code Playgroud)

这里我们使用一个虚构的ImmutableSet类型和Set::isMutable方法,在任何一种情况下,记录都是使用规范构造函数创建的 - 很好。不幸的是它不存在!

据我所知,内置集合类型(在 Java 10 中引入)是隐藏的,即无法确定集合是否不可变(除了尝试修改它)。

我们可以使用 Guava,但是当 99% 的功能已经在核心库中时,这似乎有点过分了。或者,有 Maven 插件可以测试注释为不可变的类,但这又是一个创可贴而不是解决方案。

是否有任何纯 Java 机制来强制执行不可变集合?

java immutability java-record java-16

13
推荐指数
1
解决办法
261
查看次数

如何在 Java 17 中通过反射获取所有记录字段及其值?

我上过一堂课:

class A {
   public final Integer orgId;
}
Run Code Online (Sandbox Code Playgroud)

我将其替换为Java 17中的记录:

record A (Integer orgId) {
}
Run Code Online (Sandbox Code Playgroud)

另外,我有一个通过反射进行验证的代码,该代码适用于常规类,但不适用于记录:

Field[] fields = obj.getClass().getFields(); //getting empty array here for the record
for (Field field : fields) {
}
Run Code Online (Sandbox Code Playgroud)

在 Java 17 中通过反射获取 Record 对象字段及其值的正确方法是什么?

java reflection java-record java-17

13
推荐指数
1
解决办法
7679
查看次数

Java 记录和空对象模式?

有没有办法用 Java 记录做空对象?对于课程,我会这样做:

public class Id {

  public static final Id NULL_ID = new Id();

  private String id;

  public Id(String id) {
    this.id = Objects.requireNonNull(id);
  }

  private Id() {}
}
Run Code Online (Sandbox Code Playgroud)

但这不起作用,因为每个构造函数都需要经过规范的 ( Id(String id)构造函数,而我不能只是调用super()来绕过不变量。

public record Id(String id) {
  public static final Id NULL_ID = null; // how?

  public Id {
    Objects.requireNonNull(id);
    // ...
  }
}
Run Code Online (Sandbox Code Playgroud)

现在我解决了这个问题

public Id {
  if (NULL_OBJECT != null)
    Objects.requireNonNull(id);
}
Run Code Online (Sandbox Code Playgroud)

但这感觉不对,并且容易出现并发问题。

我还没有发现很多关于记录背后的设计思想的讨论,这可能已经讨论过了。如果像这样保持简单,那是可以理解的,但感觉很尴尬,我已经在小样本中多次遇到这个问题。

java null-object-pattern java-14 java-record

11
推荐指数
2
解决办法
711
查看次数

如何使用 Java 记录断言 hasProperty?

我在测试中有一段代码,使用 Hamcrest 2.2 检查结果列表是否包含某些属性:

assertThat(result.getUsers(), hasItem(
    hasProperty("name", equalTo(user1.getName()))
));
assertThat(result.getUsers(), hasItem(
    hasProperty("name", equalTo(user2.getName()))
));
Run Code Online (Sandbox Code Playgroud)

NameDto是普通班级时,这工作得很好。但是在我将其更改为 a 之后Record,HamcresthasProperty抱怨没有名为 的属性name

java.lang.AssertionError:
Expected: a collection containing hasProperty("name", "Test Name")
     but: mismatches were: [No property "name", No property "name"]
Run Code Online (Sandbox Code Playgroud)

是否有其他匹配器可以用来实现与以前相同的匹配?或者我可以使用其他一些解决方法来让它处理记录?

java unit-testing hamcrest java-record java-16

11
推荐指数
2
解决办法
510
查看次数

Record 无法从构造函数获取参数名称?

想看看如何在 Java 16(和 15 个相同的行为)下使用带有反射的 Records

public record RecordTest2(int id, int something, double total, LocalDateTime createdOn) {

    public RecordTest2(int id, int something, double total) {
        this(id, something, total, LocalDateTime.now());
    }
}
Run Code Online (Sandbox Code Playgroud)

查看规范构造函数,我确实看到了参数名称,但没有看到其他参数名称。

var recordTest2 = new RecordTest2(1, 2, 3.0, LocalDateTime.now());
Class<?> objectClass = recordTest2.getClass();

Constructor<?>[] constructors = objectClass.getConstructors();

for (Constructor<?> con : constructors) {
    System.out.println(con.getName());
    Parameter[] parameters = con.getParameters();
    for (Parameter parameter : parameters) {
        System.out.printf("param: %s\n", parameter.getName());
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

net.sf.persism.dao.records.RecordTest2
param: arg0
param: arg1
param: arg2
net.sf.persism.dao.records.RecordTest2
param: …
Run Code Online (Sandbox Code Playgroud)

java constructor java-record java-16

11
推荐指数
1
解决办法
319
查看次数

即使它是关键字,使用“record”作为变量名是否合法?

这令人惊讶:我能够用该名称声明一个变量,record即使它现在已成为关键字。看看这个:

public class Main {
    
    static class Foo {
        void bar() { System.out.println("Foo.bar"); }
    }
    
    record R (int a) {}
    
    public static void main(String[] args) {
        Foo record = new Foo();
        record.bar();
        
        R r = new R(5);
        System.out.println(r);
    }
}
Run Code Online (Sandbox Code Playgroud)

当使用 Java 17 编译并运行时,会给出:

Foo.bar
R[a=5]
Run Code Online (Sandbox Code Playgroud)

我原以为这会导致错误,就像尝试声明名为 的变量时的情况一样class。据我所知,Java 人员非常小心,不破坏现有代码,因此我认为这可能是一个经过深思熟虑的选择。

(你甚至不能声明一个名为 name 的变量,const因为它const Java 中的关键字。)

java jls java-record java-17

11
推荐指数
2
解决办法
2034
查看次数

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

我一直在使用以下名为 City

@ToString
@AllArgsConstructor
public class City {
    Integer id;
    String name;
}
Run Code Online (Sandbox Code Playgroud)

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

record CityRecord(Integer id, String name) {} // much cleaner!
Run Code Online (Sandbox Code Playgroud)

但是转向这样的表示,我们的单元测试之一开始失败。这些测试在内部处理从 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()));
Run Code Online (Sandbox Code Playgroud)

上面的代码断言 true 包含 4 个键,每个键占其出现的 1 个。对于记录表示,结果中的键不超过 3 个Map。是什么导致了这种情况,应该有什么方法来解决这个问题?

java compatibility java-14 java-record

10
推荐指数
1
解决办法
280
查看次数

IntelliJ 不提供将类转换为记录的选项

我有一大组 POJO 类(100 多个),我想将它们转换为 Java 记录。我想自动化这个过程。

我使用的是 Java 18 (Amazon Coretto JDK) 和 IntelliJ 2022.1.4(终极版):Build #IU-221.6008.13, built on July 18, 2022

coretto-18被配置为模块的默认VM。

我遵循了 IntelliJ 文档(https://www.jetbrains.com/idea/guide/tips/convert-to-record/),但上下文操作不会显示选项“转换为记录”(预期) 。

在此输入图像描述

intellij-idea java-record

9
推荐指数
1
解决办法
3799
查看次数