技術筆記 / Java

在我們常用不可修改DTO常用這種寫法(例如打包的參數) ```java= public static class FC1{ public final ZonedDateTime start; public final String me;

    public FC1(ZonedDateTime start, String me) {
        this.start = start;
        this.me = me;
    }
}
現在新版多了個簡易的寫法如下
```java=
    public  record R1(ZonedDateTime start, String me){    }

新舊版本使用如下 ```java= public static void main(String[] args) { var fc1 =new FC1(ZonedDateTime.now(),"sss"); System.out.println("fc1 start="+fc1.start+" me="+fc1.me); var r1 = new R1(ZonedDateTime.now(),"sss"); System.out.println("r1 start="+r1.start+" me="+r1.me); } // fc1 start=2023-07-04T15:23:23.562880400+08:00[Asia/Taipei] me=sss // r1 start=2023-07-04T15:23:23.573739900+08:00[Asia/Taipei] me=sss


# 使用 lombok @Builder
在舊版時我們常用 @Builder 搭配 final field 的做法,現在在Record也可以使用
```java=
 @Builder
    public static class FC1{
        public final ZonedDateTime start;
        public final String me;
    }

    @Builder
    public  record R1(ZonedDateTime start, String me){    }

    public static void main(String[] args) {
        var fc1 =FC1.builder().start(ZonedDateTime.now()).me("BBB").build();
        System.out.println("fc1 start="+fc1.start+" me="+fc1.me);
        var r1 = R1.builder().start(ZonedDateTime.now()).me("BBB").build();
        System.out.println("r1 start="+r1.start+" me="+r1.me);
    }

序列化的部分

在final field 在序列化通常都要做特殊處理才能用或是放棄final,Record則無這限制 ```java= public static void main(String[] args) { String json =QuickMap.genSimple().add("start",99).add("me","zzz").toJson(); var r1 = JsonUtils.loadByJson(json,R1.class); System.out.println("r1 start="+r1.start+" me="+r1.me); var fc1 =JsonUtils.loadByJson(json,FC1.class); System.out.println("fc1 start="+fc1.start+" me="+fc1.me); }

line:5 執行會throw exception
```shell!
Exception in thread "main" net.bzk.infrastructure.ex.BzkRuntimeException: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `net.bzk.infrastructure.TestRecord$FC1` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: (String)"{"start":99,"me":"zzz"}"; line: 1, column: 2]

在Jackson這裡需改成 ```java= public static class FC1 { public final int start; public final String me;

    @Builder
    public FC1(@JsonProperty("start") int start, @JsonProperty("me") String me) {
        this.start = start;
        this.me = me;
    }
}
# @EqualsAndHashCode
上述幾乎都是 Record 可以取代原本 final field 的寫法,現在來說 Record 的限制, lombok @EqualsAndHashCode 可以直接產生 defaut field Equals 和 HashCode ,但是無法使用在 Record

```java=
    @EqualsAndHashCode
    public static class FC1 {
        ...


    @Builder
    @EqualsAndHashCode
    public static record R1(int start, String me) {
        ...
    // throw error: @EqualsAndHashCode is only supported on a class.
    @EqualsAndHashCode        

結論

在無需使用 custom Equals 和 HashCode methdo,基本上可以用 Record 來替代 final field class 的寫法

在 GitHub 看原文