Immutable class = object không đổi trạng thái sau khi tạo. Quy tắc viết:
1. Class khai báo final — chặn subclass override method làm lộ/đổi state.
2. Mọi field private final.
3. Không có setter — state chỉ gán 1 lần qua constructor.
4. Field là mutable object (List, Date, mảng...) → defensive copy cả 2 chiều: copy khi nhận vào constructor, copy (hoặc bọc List.copyOf()/unmodifiable) khi trả ra từ getter — nếu không, bên ngoài giữ reference gốc vẫn sửa được.
5. Muốn "sửa" → trả object mới (kiểu String.replace(), LocalDate.plusDays()).
Lợi ích: thread-safe tự nhiên (không cần lock), an toàn làm key HashMap/element của Set, dễ reason và cache.
Có sẵn trong JDK: String, wrapper (Integer, Long...), BigDecimal, LocalDate/LocalDateTime.
Java 16+: dùng record — immutable gọn nhất (tự sinh constructor, accessor, equals/hashCode) — nhưng vẫn phải tự lo defensive copy nếu component là mutable.
An immutable class = an object whose state never changes after creation. The rules:
1. Declare the class final — prevents subclasses from overriding methods to expose/alter state.
2. Every field private final.
3. No setters — state is assigned once via the constructor.
4. Mutable-object fields (List, Date, arrays...) → defensive copies both ways: copy on the way in (constructor) and copy (or wrap with List.copyOf()/unmodifiable) on the way out (getters) — otherwise an outside holder of the original reference can still mutate it.
5. To "modify" → return a new object (like String.replace(), LocalDate.plusDays()).
Benefits: naturally thread-safe (no locking), safe as HashMap keys/Set elements, easy to reason about and cache.
Built-in examples: String, wrappers (Integer, Long...), BigDecimal, LocalDate/LocalDateTime.
Java 16+: use a record — the most concise immutable form (generated constructor, accessors, equals/hashCode) — but you still handle defensive copies for mutable components yourself.