Throwable
├── Error (JVM, không bắt)
└── Exception
├── RuntimeException → UNCHECKED (NPE, IllegalArgument...)
└── (mọi Exception khác) → CHECKED (IOException, SQLException...)| Checked | Unchecked | |
|---|---|---|
| Compiler bắt buộc xử lý | ✅ try-catch hoặc throws | ❌ |
| Ý nghĩa | Lỗi có thể khôi phục | Bug lập trình |
String readFile(String path) throws IOException { // checked
return Files.readString(Path.of(path));
}
void divide(int a, int b) { int x = a / b; } // unchecked — ArithmeticExceptionTranh cãi thực tế: checked exception nghe có vẻ tốt nhưng gây:
- Boilerplate khủng (try-catch / throws lan tầng).
- Lambda không thân thiện: Stream.map(f -> readFile(f)) không compile.
- Anti-pattern phổ biến: catch (Exception e) {} nuốt lỗi.
Xu hướng hiện đại (Spring, JPA, Kotlin): ưu tiên unchecked. Spring chuyển hết DB exception về DataAccessException (unchecked).
Quy tắc đặt exception mới:
- Caller có thể và nên xử lý (retry, fallback) → checked.
- Bug lập trình → unchecked, để fail-fast lên global handler.
- Đa số case chọn unchecked trừ khi có lý do mạnh.
Throwable
├── Error (JVM, do not catch)
└── Exception
├── RuntimeException → UNCHECKED (NPE, IllegalArgument...)
└── (any other Exception)→ CHECKED (IOException, SQLException...)| Checked | Unchecked | |
|---|---|---|
| Compiler forces handling | ✅ try-catch or throws | ❌ |
| Intent | Recoverable condition | Programming bug |
String readFile(String path) throws IOException { // checked
return Files.readString(Path.of(path));
}
void divide(int a, int b) { int x = a / b; } // unchecked — ArithmeticExceptionThe debate: checked sounds good but causes:
- Boilerplate (nested try-catch, propagating throws).
- Lambda-unfriendly: Stream.map(f -> readFile(f)) does not compile.
- Anti-pattern: catch (Exception e) {} swallowing errors.
Modern trend (Spring, JPA, Kotlin): prefer unchecked. Spring converts every DB exception to DataAccessException (unchecked).
Rule for new exceptions:
- Caller can and should handle (retry, fallback) → checked.
- Programming bug → unchecked, fail-fast to a global handler.
- Most cases pick unchecked unless there is a strong reason.