Java 中你絕對沒用過的一個關鍵字?


layout: post
categories: Java
title: Java 中你絕對沒用過的一個關鍵字?
tagline: by 子悠
tags:

  • 子悠

前面的文章給大家介紹了如何自定義一個不可變類,沒看過的小夥伴建議去看一下,這節課給大家介紹一個 Java 中的一個關鍵字 Record,那 Record 關鍵字跟不可變類有什麼關係呢?看完今天的文章你就知道了。友情提示 Record 關鍵字在 Java14 過後才支持的,所以是不是被阿粉說中了,還在使用 Java 8 的你一定沒用過!

不可變類

我們先看一下之前定義的不可變類,代碼如下。

package com.example.demo.immutable;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public final class Teacher {
  private final String name;
  private final List<String> students;
  private final Address address;
  private final Map<String, String> metadata;

  public Teacher(String name, List<String> students, Address address, Map<String, String> metadata) {
    this.name = name;
    this.students = students;
    this.address = address;
    this.metadata = metadata;
  }

  public String getName() {
    return name;
  }

  public List<String> getStudents() {
    return new ArrayList<>(students);
//    return students;
  }

  public Address getAddress() {
//    return address;
    return address.clone();
  }

  public Map<String, String> getMetadata() {
    return new HashMap<>(metadata);
//    return metadata;
  }
}

如果你複製上面代碼到 IDEA 中,並且剛好你的 JDK 版本是 Java14 之後的話,那麼你就會看到下面這個提示,提示我們可以將 Teacher 這個不可變類轉換為 Record。怎麼樣是不是很懵,沒關係,我們按照提示操作一下看看會發生什麼。

點完之後我們的代碼會變成下面的樣子

package com.example.demo.immutable;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public record Teacher(String name, List<String> students, Address address, Map<String, String> metadata) {

  @Override
  public List<String> students() {
    return new ArrayList<>(students);
//    return students;
  }

  @Override
  public Address address() {
//    return address;
    return address.clone();
  }

  @Override
  public Map<String, String> metadata() {
    return new HashMap<>(metadata);
//    return metadata;
  }
}

仔細一看你會發現,這是什麼情況,record 是什麼關鍵字,然後類名後面怎麼還有參數?乍一看還以為變成一個方法了。此外我們之前的測試代碼不用修改任何邏輯,照樣可以正常運行,是不是很神奇?這就是 Record 關鍵字的特性。

Record 關鍵字

看完了 Record 關鍵字的 case ,我們來聊一下 Record 關鍵字是怎麼用的,以及它有什麼特性。

  1. Record 關鍵定義的類是不可變類;
  2. Record 定義的類需要將所有成員變量通過參數的形式定義;
  3. Record 定義的類默認會生成全部參數的構造方法;
  4. Record 定義的類中可以定義靜態方法;
  5. Record 定義的類可以提供緊湊的方式進行參數校驗;

上面的五點裏面前三點我們在之前的例子中都可以看出來,在定義和使用的時候可以明顯的看到,如下所示。

public record Teacher(String name, List<String> students, Address address, Map<String, String> metadata) {
}//1,2
 Teacher teacher = new Teacher("Java極客技術", students, address, metadata);//3

下面我們看下第四點和第五點,關於第四點我們可以在 Record 類中定義靜態方法用來默認初始化對象,如下所示,通過這種方式我們可以寫出更簡潔的代碼。

  public static Teacher of() {
    return new Teacher("Java極客技術", new ArrayList<>(), new Address(), new HashMap<>());
  }

  public static Teacher of(String name) {
    return new Teacher(name, new ArrayList<>(), new Address(), new HashMap<>());
  }

在使用的時候,我們就可以直接通過類名引用靜態方法就可以了,如下所示

 Teacher teacher = Teacher.of();

接下來我們看看什麼叫緊湊的方式進行參數校驗,試想一下,如果我們需要校驗在溝通 Teacher 對象的時候,student 成員變量不能為空,在我們以前的寫法裏面只要在構造方法裏面進行一下判空就可以了,但是對於 Record 的形式,我們沒有顯示的創建構造方法,那我們應該如何進行判斷呢?答案如下

  public Teacher {
    if (null == students || students.size() == 0) {
      throw new IllegalArgumentException();
    }
  }

可以看到我們通過一種緊湊的構造方法的形式來進行了參數的校驗,這種寫法跟我們普通的構造方法是不一樣的,沒有方法參數,怎麼樣是不是很神奇。

總結

有的人說 JavaRecord 的新特性是為了讓大家不使用 Lombok 的,阿粉倒是覺得不見得,畢竟 Lombok 用起來是真的香,而且 Record 也只能是定義不可變類,在某些情況下使用還是有局限性的,不可變類的使用場景並不是很多。

更多優質內容歡迎關注公眾號【Java 極客技術】,我準備了一份面試資料,回復【bbbb07】免費領取。希望能在這寒冷的日子裏,幫助到大家。