Java Record
Java 14 引入(Java 16 正式),Record 是一種簡潔的方式來建立不可變的資料類別。
基本語法
// 定義 Record
public record Person(String name, int age) {}
// 使用
Person person = new Person("Alice", 25);
System.out.println(person.name()); // Alice
System.out.println(person.age()); // 25
Record 自動提供
Record 會自動產生:
- 所有欄位的 getter 方法(沒有 get 前綴)
equals()方法hashCode()方法toString()方法- 全參數建構子
等同於傳統類別
// 這個 Record
public record Person(String name, int age) {}
// 等同於以下傳統類別
public final class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String name() { return name; }
public int age() { return age; }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Person[name=" + name + ", age=" + age + "]";
}
}
自訂建構子
緊湊建構子
public record Person(String name, int age) {
// 緊湊建構子:不需要參數列表
public Person {
// 驗證
if (name == null || name.isBlank()) {
throw new IllegalArgumentException("名稱不能為空");
}
if (age < 0) {
throw new IllegalArgumentException("年齡不能為負數");
}
// 正規化
name = name.trim();
}
}
自訂建構子
public record Point(int x, int y) {
// 原點建構子
public Point() {
this(0, 0);
}
// 只有 x 的建構子
public Point(int x) {
this(x, 0);
}
}
Point origin = new Point(); // (0, 0)
Point xOnly = new Point(5); // (5, 0)
Point full = new Point(3, 4); // (3, 4)
新增方法
public record Rectangle(double width, double height) {
// 計算面積
public double area() {
return width * height;
}
// 計算周長
public double perimeter() {
return 2 * (width + height);
}
// 靜態工廠方法
public static Rectangle square(double side) {
return new Rectangle(side, side);
}
}
Rectangle rect = new Rectangle(3, 4);
System.out.println(rect.area()); // 12.0
System.out.println(rect.perimeter()); // 14.0
Rectangle square = Rectangle.square(5);
實作介面
public interface Printable {
void print();
}
public record Book(String title, String author) implements Printable {
@Override
public void print() {
System.out.println(title + " by " + author);
}
}
Record 的限制
- 所有欄位都是
final(不可變) - 不能繼承其他類別
- 不能宣告實例變數
- 是
final類別,不能被繼承
// 錯誤:不能繼承
// public record Employee(String name) extends Person { }
// 錯誤:不能有實例變數
// public record Person(String name) {
// private int age; // 錯誤
// }
實際應用
DTO(資料傳輸物件)
public record UserDTO(Long id, String name, String email) {}
// API 回應
public record ApiResponse<T>(int code, String message, T data) {}
複合鍵
public record CompositeKey(String part1, String part2) {}
Map<CompositeKey, String> map = new HashMap<>();
map.put(new CompositeKey("a", "b"), "value");
回傳多個值
public record MinMax(int min, int max) {}
public MinMax findMinMax(int[] array) {
int min = Arrays.stream(array).min().orElse(0);
int max = Arrays.stream(array).max().orElse(0);
return new MinMax(min, max);
}
MinMax result = findMinMax(new int[]{3, 1, 4, 1, 5});
System.out.println(result.min()); // 1
System.out.println(result.max()); // 5
設定類別
public record DatabaseConfig(String url, String username, String password) {}
public record ServerConfig(String host, int port, DatabaseConfig database) {}
Record 和模式匹配 (Java 19+)
public record Point(int x, int y) {}
// 模式匹配
Object obj = new Point(3, 4);
if (obj instanceof Point(int x, int y)) {
System.out.println("x = " + x + ", y = " + y);
}
// switch 中使用
String result = switch (obj) {
case Point(int x, int y) -> "Point at (" + x + ", " + y + ")";
default -> "Unknown";
};
Record vs Class
| 特性 | Record | Class |
|---|---|---|
| 可變性 | 不可變 | 可變 |
| 繼承 | 不可繼承 | 可繼承 |
| 樣板程式碼 | 少 | 多 |
| 用途 | 資料載體 | 一般用途 |