Họ đang đo gì
Bạn có nghĩ về người GỌI hàm của mình không, và có nhất quán trong cả codebase không.
Trả lời ngắn~30 giây
Quy tắc gốc: checked cho tình huống người gọi có thể xử lý được và nên được nhắc; unchecked cho lỗi lập trình. Thực tế thì phần lớn framework hiện đại, kể cả Spring, nghiêng hẳn về unchecked — vì checked exception lan qua mọi tầng chữ ký và đẩy người ta tới catch (Exception e) {}. Mình dùng unchecked mặc định, và checked chỉ khi người gọi thật sự có phương án thay thế.
Giải thích sâu
Lập luận phản đối checked exception mạnh nhất không phải “viết dài dòng” mà là nó phá tính đóng gói: thêm một lời gọi có thể ném IOException ở tầng sâu buộc bạn sửa chữ ký của mọi hàm trên đường đi, nghĩa là chi tiết cài đặt rò lên tận API công khai. Đó cũng là lý do các API dạng hàm — Stream, Optional, CompletableFuture — gần như không dùng được với lambda ném checked exception.
Nhưng lập luận bênh vực cũng có phần đúng ở biên hệ thống: khi bạn gọi ra ngoài — file, mạng, tiến trình khác — thất bại là chuyện bình thường chứ không phải bug, và bắt người gọi nhìn thấy điều đó có giá trị. Câu trả lời chín chắn là phân biệt theo lớp: biên ngoài dùng checked hoặc kiểu kết quả tường minh, còn bên trong domain thì unchecked.
Điều quan trọng hơn cả hai lựa chọn là đừng nuốt exception. catch (Exception e) { log.error(e); } rồi chạy tiếp là cách biến một lỗi rõ ràng thành dữ liệu sai âm thầm. Nếu không xử lý được thì để nó bay lên, hoặc bọc lại kèm ngữ cảnh (throw new OrderFailed("order " + id, e)) — nhớ truyền cause, vì mất stack trace gốc là mất luôn khả năng điều tra.
Câu hỏi tiếp theo họ sẽ hỏi
?finally có luôn chạy không?
Gần như luôn, trừ System.exit(), JVM chết, hoặc luồng bị kill. Bẫy đáng nhớ: return trong finally NUỐT exception đang bay lên, và đó là lỗi rất khó tìm. try-with-resources nên được ưu tiên vì nó đóng tài nguyên đúng thứ tự và giữ được exception gốc dưới dạng suppressed.
Trả lời thế này là mất điểm
catch (Exception e) {}rỗng, hoặc chỉe.printStackTrace(). Cả hai đều là “tôi đã thấy lỗi và quyết định giấu nó”.- Dùng exception cho luồng điều khiển bình thường. Tạo stack trace rất đắt, và nó làm mất ý nghĩa của từ “ngoại lệ”.