RuntimeException: Khi code 'tự va' mà không báo trước!
Java – OOP

RuntimeException: Khi code 'tự va' mà không báo trước!

Author

Admin System

@root

Ngày xuất bản

22 Mar, 2026

Lượt xem

1 Lượt

RuntimeException

Genz thân mến, hôm nay chúng ta sẽ mổ xẻ một khái niệm mà nhiều khi mấy đứa cứ thấy nó xuất hiện mà không hiểu 'thằng cha' này từ đâu chui ra: RuntimeException.

1. RuntimeException là gì? Để làm gì? (Giải mã kiểu Gen Z)

Nghe anh Creyt giảng đây! Tưởng tượng thế này: cuộc đời lập trình của mấy đứa y như đi trên đường vậy. Có những cái đèn đỏ (Checked Exception) mà mấy đứa bắt buộc phải dừng lại, phải khai báo trước là 'ê, tao phải xử lý thằng này nha'. Ví dụ như file không tồn tại, kết nối mạng đứt đoạn... đó là những thứ mình biết trước là có thể xảy ra và phải chuẩn bị tinh thần để xử lý.

Còn RuntimeException á? Nó giống như việc mấy đứa đang đi đường bình thường, tự nhiên vấp cục đá tàng hình vậy! Hay đang lái xe mà thằng cha nào đó tự nhiên băng ngang đường không xi nhan, không báo trước. Nó xảy ra đột ngột, không được báo trước khi biên dịch (compile time), mà chỉ bung bét ra khi chương trình đang chạy (runtime).

Nói thẳng ra, RuntimeException thường là lỗi của lập trình viên! Đúng vậy, lỗi do mình ẩu, mình không lường trước được các trường hợp logic mà đáng lẽ ra mình phải xử lý. Ví dụ: cố gắng truy cập phần tử thứ 100 của một mảng chỉ có 10 phần tử (ArrayIndexOutOfBoundsException), hay chia một số cho 0 (ArithmeticException), hoặc tệ hơn là cố gắng thao tác với một đối tượng null (NullPointerException).

Để làm gì? Nó là cách Java 'mắng vốn' mấy đứa: 'Ê thằng kia! Mày viết code sai logic rồi! Sửa lại đi!'. Nó không bắt mấy đứa phải try-catch ngay từ đầu vì nó nghĩ rằng, nếu code đúng logic thì những lỗi này không bao giờ xảy ra.

2. Code Ví Dụ Minh Hoạ Rõ Ràng

Để mấy đứa dễ hình dung, anh cho vài ví dụ kinh điển của RuntimeException:

Ví dụ 1: NullPointerException – 'Thằng cha' này không tồn tại!

public class RuntimeExceptionDemo {

    public static void main(String[] args) {
        String tenBan = null;

        // Cố gắng gọi phương thức trên một đối tượng null
        try {
            int doDaiTen = tenBan.length(); // Bùm! NullPointerException
            System.out.println("Độ dài tên: " + doDaiTen);
        } catch (NullPointerException e) {
            System.err.println("Ơ kìa! Tên bạn đang là NULL mà đòi đo độ dài à? Sửa lại đi chứ!\n" + e.getMessage());
            // Log lỗi hoặc xử lý khác
        }

        System.out.println("Chương trình tiếp tục chạy (sau khi xử lý lỗi).");
    }
}

Ví dụ 2: ArrayIndexOutOfBoundsException – Vượt quá giới hạn cho phép!

public class ArrayErrorDemo {

    public static void main(String[] args) {
        int[] soMayMan = {1, 7, 9, 24, 68};

        try {
            // Cố gắng truy cập phần tử thứ 5 (index 4) rồi phần tử thứ 10 (index 9)
            System.out.println("Phần tử thứ 5: " + soMayMan[4]);
            System.out.println("Phần tử thứ 10: " + soMayMan[9]); // Bùm! ArrayIndexOutOfBoundsException
        } catch (ArrayIndexOutOfBoundsException e) {
            System.err.println("Mảng có 5 phần tử (0-4) mà đòi truy cập phần tử thứ 10 là sao? Sai rồi!\n" + e.getMessage());
        }
    }
}

Ví dụ 3: Custom RuntimeException – Tạo lỗi 'tự va' của riêng mình

Đôi khi, mấy đứa muốn tạo ra một lỗi logic đặc thù của ứng dụng mà không muốn người dùng (của thư viện/module của mấy đứa) bị ép phải catch. Lúc đó, Custom RuntimeException là lựa chọn 'chất'!

// Bước 1: Định nghĩa Custom RuntimeException
class KhongDuTienException extends RuntimeException {
    public KhongDuTienException(String message) {
        super(message);
    }
}

// Bước 2: Sử dụng trong logic nghiệp vụ
public class GiaoDichTaiChinh {

    private double soDuTaiKhoan;

    public GiaoDichTaiChinh(double soDu) {
        this.soDuTaiKhoan = soDu;
    }

    public void rutTien(double soTienCanRut) {
        if (soTienCanRut <= 0) {
            throw new IllegalArgumentException("Số tiền rút phải lớn hơn 0!");
        }
        if (soTienCanRut > soDuTaiKhoan) {
            // Ném RuntimeException của riêng mình
            throw new KhongDuTienException("Số dư hiện tại " + soDuTaiKhoan + " không đủ để rút " + soTienCanRut + " VND.");
        }
        soDuTaiKhoan -= soTienCanRut;
        System.out.println("Rút thành công! Số dư mới: " + soDuTaiKhoan);
    }

    public static void main(String[] args) {
        GiaoDichTaiChinh tk = new GiaoDichTaiChinh(1000000);

        try {
            tk.rutTien(500000); // OK
            tk.rutTien(700000); // Bùm! KhongDuTienException
        } catch (KhongDuTienException e) {
            System.err.println("Giao dịch thất bại: " + e.getMessage());
        } catch (IllegalArgumentException e) {
            System.err.println("Lỗi đầu vào: " + e.getMessage());
        }
    }
}
Illustration

3. Mẹo (Best Practices) để Ghi Nhớ và Dùng Thực Tế

  • Đừng lạm dụng try-catch(Exception e) chung chung: Mấy đứa đừng có mà lười biếng, thấy lỗi là quất ngay catch(Exception e) tùm lum. Đó là 'bịt mắt' lỗi chứ không phải xử lý. Hãy chỉ catch những RuntimeException cụ thể mà mấy đứa có thể xử lý một cách có ý nghĩa (ví dụ: thông báo cho người dùng biết lỗi nhập liệu, log lại lỗi để dev sửa). Hầu hết các RuntimeException nên được để cho chương trình crash (hoặc được xử lý ở tầng cao nhất của ứng dụng) để dev biết mà sửa bug gốc.
  • Fix gốc rễ vấn đề, đừng chỉ 'bịt lỗ': RuntimeException là tiếng chuông cảnh tỉnh rằng code của mấy đứa có lỗi logic hoặc thiếu kiểm tra đầu vào. Thay vì cứ catch rồi bỏ qua, hãy đào tận gốc rễ: kiểm tra null trước khi dùng, kiểm tra biên mảng, kiểm tra điều kiện chia cho 0, validate input người dùng... Đó mới là cách làm của một dev chuyên nghiệp!
  • Dùng RuntimeException cho lỗi lập trình: Nếu lỗi đó là do dev viết code sai, không lường trước được, thì cứ để RuntimeException bung bét. Nó sẽ giúp mấy đứa phát hiện bug sớm hơn.
  • Khi nào tạo Custom RuntimeException? Khi mấy đứa muốn signal một lỗi logic cụ thể của ứng dụng mà không muốn ép người dùng của API/thư viện của mình phải catch. Ví dụ: InsufficientFundsException (như trên), UserNotFoundException (nếu coi việc không tìm thấy user là lỗi logic của hệ thống chứ không phải lỗi 'mong đợi' từ bên ngoài).
  • RuntimeException là 'lời nhắc nhở' của compiler: Nó không bắt mấy đứa khai báo vì nó tin rằng, nếu mấy đứa viết code đúng chuẩn, những lỗi này sẽ không bao giờ xảy ra. Hãy sống theo niềm tin đó!

4. Ví dụ Thực Tế Các Ứng Dụng/Website đã Ứng Dụng

Hầu hết mọi ứng dụng, website lớn nhỏ đều 'sống chung' với RuntimeException:

  • Hệ thống E-commerce (ví dụ: Shopee, Lazada): Khi người dùng cố gắng thêm một sản phẩm vào giỏ hàng mà sản phẩm đó đã hết hàng hoặc không tồn tại, thay vì báo Checked Exception (buộc mọi nơi gọi phải catch), hệ thống có thể ném một RuntimeException dạng ProductNotFoundException hoặc OutOfStockException (nếu coi đây là lỗi logic nghiệp vụ mà không cần caller phải catch tường minh) để xử lý ở tầng cao hơn, hoặc log lại để dev kiểm tra.
  • Ngân hàng (ví dụ: Vietcombank, Techcombank): Trong ví dụ KhongDuTienException ở trên, việc tài khoản không đủ tiền để rút là một lỗi nghiệp vụ quan trọng. Nếu coi đây là một lỗi mà hệ thống cần phải dừng giao dịch và thông báo rõ ràng, và không muốn mọi hàm transferMoney phải throws InsufficientFundsException, thì một RuntimeException là phù hợp.
  • Frameworks (ví dụ: Spring Boot): Các framework hiện đại như Spring rất hay 'bọc' (wrap) các Checked Exception thành RuntimeException để làm cho code API của họ sạch sẽ hơn, ít phải try-catch lằng nhằng ở mọi nơi. Ví dụ, một SQLException (Checked) có thể được Spring chuyển thành DataAccessException (là một RuntimeException) để dev tập trung vào logic nghiệp vụ hơn.

5. Thử Nghiệm Đã Từng và Hướng Dẫn Nên Dùng Cho Case Nào

Thử nghiệm đã từng: Hồi xưa anh Creyt mới vào nghề, cũng như mấy đứa, thấy RuntimeException là hoảng hồn, cứ tưởng là lỗi gì ghê gớm lắm. Cứ cố gắng try-catch mọi thứ. Sau này mới ngộ ra, RuntimeException không phải để catch mà là để sửa! Anh đã từng mất cả ngày trời debug một NullPointerException chỉ vì quên kiểm tra một đối tượng trả về từ database có thể là null.

Nên dùng cho case nào?

  • Lỗi lập trình (Programmer Errors): Đây là trường hợp phổ biến nhất. NullPointerException, IndexOutOfBoundsException, IllegalArgumentException (khi tham số truyền vào không hợp lệ)... Những lỗi này cho thấy có một vấn đề cơ bản trong logic hoặc cách sử dụng API của mấy đứa. Hãy để chúng xảy ra và sửa code!
  • Lỗi không thể phục hồi (Unrecoverable Errors): Những lỗi mà khi xảy ra thì chương trình không thể tiếp tục hoạt động một cách hợp lý được nữa. Ví dụ: hệ thống không thể khởi tạo một tài nguyên quan trọng, hoặc một service cần thiết không thể kết nối.
  • Lỗi nghiệp vụ mà không muốn ép buộc caller xử lý: Như ví dụ KhongDuTienException. Mấy đứa muốn thông báo lỗi này nhưng không muốn mọi hàm gọi rutTien phải throwscatch. Thay vào đó, nó sẽ được xử lý ở tầng cao hơn (ví dụ: tầng Controller trong ứng dụng web).

Khi nào KHÔNG nên dùng RuntimeException?

  • Lỗi có thể phục hồi và dự đoán được: Ví dụ: File không tìm thấy, mất kết nối mạng, database down. Đây là những tình huống bên ngoài hệ thống của mấy đứa, có thể xảy ra và mấy đứa nên cung cấp cách để người dùng hoặc hệ thống phục hồi. Lúc này, Checked Exception là lựa chọn đúng đắn, nó ép buộc dev phải xử lý.

Nhớ nhé Genz, RuntimeException không phải là 'kẻ thù', nó là 'người bạn' giúp mấy đứa viết code chất lượng hơn bằng cách chỉ ra những lỗ hổng trong logic của mình. Hãy học cách lắng nghe nó!

Thuộc Series: Java – OOP

Bài giảng này được tự động xuất bản ngẫu nhiên từ thư viện kiến thức. Đừng quên đón xem các Từ khoá Hướng Dẫn tiếp theo nhé!

#tech #cyberpunk #laravel
Chỉnh sửa bài viết

Bình luận (0)

Vui lòng Đăng Nhập để Bình luận

Hỗ trợ Markdown cơ bản
Nguyễn Văn A
1 ngày trước

Tính năng này đỉnh quá ad ơi, chờ mãi mới thấy một blog Tiếng Việt có UI/UX xịn như vầy!