Record in Java

February 3, 2026

1. Tại sao cần Record? (So sánh với POJO)

Trước đây, để tạo một Class chứa dữ liệu, bạn phải viết: private fields, constructor, getters, equals(), hashCode(), và toString(). Dù dùng IDE hay Lombok, code vẫn rất rác.

Với Record, tất cả những thứ đó gói gọn trong 1 dòng:

public record UserDto(Long id, String username, String email) {}

Chỉ với dòng này, Java tự động tạo cho bạn:

  • Các trường private final (Dữ liệu trong Record là Immutable - không thể thay đổi).
  • Một Constructor với đầy đủ tham số.
  • Các phương thức truy cập (nhưng không có chữ get, ví dụ: user.username() thay vì user.getUsername()).
  • Hàm equals(), hashCode()toString() chuẩn chỉ.

2. Cách sử dụng trong thực tế

Khởi tạo và truy cập:

UserDto user = new UserDto(1L, "bach", "bach@example.com");

System.out.println(user.username()); // Truy cập field
System.out.println(user); // Tự động in ra: UserDto[id=1, username=bach, email=bach@example.com]

Thêm Validation (Compact Constructor): Bạn có thể kiểm tra dữ liệu ngay khi khởi tạo mà không cần viết lại toàn bộ Constructor:

public record UserDto(Long id, String username, String email) {
    public UserDto {
        if (id < 0) {
            throw new IllegalArgumentException("ID cannot be negative");
        }
        // Không cần gán this.id = id; Java tự làm việc đó.
    }
}

Lưu ý

  • Tính bất biến (Immutability): Record được thiết kế để không thay đổi trạng thái. Nó cực kỳ an toàn cho Multithreading và lập trình hàm.
  • Không thể kế thừa: Record mặc định là final và nó không thể kế thừa class khác (vì nó đã kế thừa java.lang.Record). Tuy nhiên, nó có thể implements các Interface.
  • Dùng tốt nhất cho:
    • Immutability Model: để hứng response value của API hay client API.
    • DTO (Data Transfer Objects): Khi lấy dữ liệu từ DB hoặc gọi API.
    • Value Objects: Các đối tượng như Money, Range, Coordinate.
    • Map keys: Vì equals và hashCode được tự động tạo rất chuẩn.

3. Khi nào KHÔNG nên dùng Record?

  • Khi bạn cần một Entity của Hibernate/JPA. Hibernate yêu cầu POJO có constructor không tham số và các trường phải thay đổi được (mutable) để Lazy Loading hoạt động. Record không đáp ứng được điều này.
  • Khi bạn cần thay đổi giá trị của các trường sau khi khởi tạo.