Từ khóa final ép buộc gán giá trị một lần tại khai báo hoặc trong constructor. Nếu muốn hành vi tương tự nhưng linh hoạt hơn (ví dụ: gán muộn, ném exception tùy chỉnh), ta có thể tự triển khai qua setter.
Mô phỏng final bằng setter có điều kiện
public class OnceAssignable {
private Integer number;
private String data;
// Chỉ gán nếu chưa có giá trị, lần 2 giữ nguyên giá trị cũ
public void setNumber(int num) {
this.number = (this.number == null) ? num : this.number;
}
// Lần 2 ném exception
public void setData(String data) {
if (this.data != null) {
throw new IllegalStateException("Không thể gán giá trị cho 'data' lần thứ hai!");
}
this.data = data;
}
public Integer getNumber() { return number; }
public String getData() { return data; }
public static void main(String[] args) {
OnceAssignable obj = new OnceAssignable();
obj.setNumber(200);
System.out.println("Lần 1: " + obj.getNumber()); // 200
obj.setNumber(500); // bị bỏ qua
System.out.println("Lần 2: " + obj.getNumber()); // vẫn 200
obj.setData("Hello");
// obj.setData("World"); // → ném IllegalStateException
}
}
Kết quả
Lần 1: 200
Lần 2: 200
So sánh với final
| Đặc điểm | final | Setter tùy chỉnh |
|---|---|---|
| Ép buộc tại compile-time | ✅ | ❌ |
| Gán muộn (lazy init) | ❌ (trừ field instance) | ✅ |
| Tùy chỉnh hành vi lần 2 | ❌ | ✅ (bỏ qua / ném exception / log...) |
| Thread-safe | ✅ (nếu khởi tạo đúng) | Cần synchronized/atomic |
Lưu ý: Trong đa luồng, hãy dùng AtomicReference hoặc synchronized để tránh race condition.