Bỏ qua để đến nội dung

Checked vs Unchecked Exception

Java có hai nhóm exception hoàn toàn khác nhau về cách trình biên dịch xử lý, và việc nhầm lẫn hai nhóm này khiến lập trình viên mới hay bối rối khi gặp lỗi biên dịch khó hiểu hoặc quên xử lý lỗi quan trọng:

import java.io.FileReader;
import java.io.IOException;
FileReader reader = new FileReader("data.txt"); // LỖI BIÊN DỊCH! Chưa xử lý IOException
int[] numbers = {1, 2, 3};
System.out.println(numbers[10]); // BIÊN DỊCH OK, nhưng ném ArrayIndexOutOfBoundsException lúc chạy

Vì sao dòng đầu bắt buộc phải xử lý lỗi ngay khi biên dịch, còn dòng sau thì không?

Java phân loại exception thành hai nhóm:

Checked exception: kế thừa từ Exception nhưng không kế thừa từ RuntimeException (ví dụ IOException, SQLException). Trình biên dịch bắt buộc bạn phải xử lý (try/catch) hoặc khai báo throws trong chữ ký phương thức - đại diện cho các lỗi có thể lường trước và nên xử lý (file không tồn tại, kết nối mạng thất bại…).

Unchecked exception: kế thừa từ RuntimeException (ví dụ NullPointerException, ArrayIndexOutOfBoundsException, ArithmeticException, IllegalArgumentException). Trình biên dịch không bắt buộc xử lý - thường đại diện cho lỗi logic của lập trình viên mà lý tưởng nhất là nên sửa code để tránh xảy ra, thay vì bắt và bỏ qua.

import java.io.FileReader;
import java.io.IOException;
// Cách 1: xử lý bằng try/catch
try {
FileReader reader = new FileReader("data.txt");
} catch (IOException e) {
System.out.println("Không đọc được file: " + e.getMessage());
}
// Cách 2: khai báo throws, đẩy trách nhiệm xử lý cho nơi gọi phương thức này
static void readFile() throws IOException {
FileReader reader = new FileReader("data.txt");
}
Throwable
├── Error (lỗi nghiêm trọng cấp hệ thống, không nên tự bắt - ví dụ OutOfMemoryError)
└── Exception
├── RuntimeException (UNCHECKED - NullPointerException, ArithmeticException,...)
└── (các Exception khác) (CHECKED - IOException, SQLException,...)
  • Với checked exception: xử lý thật sự có ý nghĩa (log, thử lại, thông báo người dùng) - tránh catch (Exception e) {} bắt rồi bỏ qua trống rỗng, che giấu lỗi thật sự
  • Với unchecked exception: ưu tiên sửa nguyên nhân gốc (kiểm tra null, kiểm tra chỉ số hợp lệ trước) thay vì bắt và bỏ qua mọi lúc mọi nơi
  • Có thể tự định nghĩa exception riêng bằng cách kế thừa Exception (checked) hoặc RuntimeException (unchecked) tùy vào việc có muốn bắt buộc nơi gọi phải xử lý hay không

Checked exception (không kế thừa RuntimeException): bắt buộc xử lý ngay lúc biên dịch (try/catch hoặc throws). Unchecked exception (kế thừa RuntimeException): không bắt buộc xử lý, thường là dấu hiệu của lỗi logic nên sửa trong code thay vì bắt và bỏ qua.