Xử lý Ngoại lệ (try-catch-finally)

Đăng ngày: 02-09-2025 18:15
học javajava cơ bảnlập trình javaxử lý ngoại lệexception handlingtry catch javafinallythrow exceptionchecked unchecked exception

Chào mừng bạn đã đến với bài 11 của series "Chinh Phục Java"! Trong quá trình lập trình, không phải lúc nào mọi thứ cũng diễn ra suôn sẻ. Có rất nhiều tình huống lỗi có thể xảy ra: người dùng nhập sai dữ liệu, file không tồn tại, mất kết nối mạng... Những sự kiện bất thường này được gọi là **Ngoại lệ (Exceptions)**. Nếu không được xử lý, chúng sẽ làm chương trình của bạn bị "crash" (dừng đột ngột).

Hôm nay, chúng ta sẽ học một trong những kỹ năng quan trọng nhất của lập trình viên chuyên nghiệp. Đó là **Xử lý Ngoại lệ (Exception Handling)**. Java cung cấp một cơ chế rất mạnh mẽ để "bắt" và xử lý các lỗi này. Nó giúp chương trình của bạn trở nên mạnh mẽ và đáng tin cậy hơn.

1. Ngoại lệ (Exception) là gì?

Ngoại lệ là một sự kiện xảy ra trong quá trình thực thi chương trình. Nó làm gián đoạn luồng chạy bình thường của code. Hãy nghĩ về nó như một tín hiệu báo động. Khi một lỗi xảy ra, Java sẽ tạo ra một đối tượng Exception. Đối tượng này chứa thông tin về lỗi, ví dụ như lỗi là gì và nó xảy ra ở đâu. Sau đó, nó sẽ "ném" (throw) đối tượng này ra.

Nếu không có cơ chế nào "bắt" (catch) lại ngoại lệ này, chương trình sẽ dừng lại. Nó sẽ in ra một loạt thông báo lỗi khó hiểu gọi là "stack trace". Mục tiêu của chúng ta là ngăn chặn điều này. Chúng ta muốn chương trình có thể phục hồi sau lỗi. Hoặc ít nhất là thông báo cho người dùng một cách thân thiện.

2. Khối `try-catch`: Bắt và Xử lý Lỗi

Công cụ chính để xử lý ngoại lệ trong Java là khối lệnh try-catch. Cú pháp của nó rất đơn giản. Bạn đặt đoạn code có nguy cơ gây ra lỗi vào bên trong khối `try`. Ngay sau đó, bạn đặt một hoặc nhiều khối `catch`. Mỗi khối `catch` sẽ xử lý một loại ngoại lệ cụ thể.

Nếu một ngoại lệ xảy ra bên trong khối `try`, luồng thực thi sẽ nhảy ngay đến khối `catch` tương ứng. Phần code còn lại trong khối `try` sẽ bị bỏ qua. Nếu không có lỗi nào xảy ra, khối `catch` sẽ không được thực thi. Hãy xem ví dụ về lỗi chia cho số không.


public class TryCatchExample {
    public static void main(String[] args) {
        try {
            // Đặt đoạn code có thể gây lỗi vào đây
            int result = 10 / 0; // Phép chia cho 0 sẽ ném ra ArithmeticException
            System.out.println("Kết quả là: " + result); // Dòng này sẽ không bao giờ được chạy
        } catch (ArithmeticException e) {
            // Khối này sẽ được thực thi khi lỗi xảy ra
            System.out.println("Đã xảy ra lỗi! Bạn không thể chia một số cho 0.");
            // e.printStackTrace(); // Dùng để in ra chi tiết lỗi khi cần debug
        }
        
        System.out.println("Chương trình tiếp tục chạy...");
    }
}

Nhờ có `try-catch`, chương trình không bị crash. Nó đã bắt được lỗi, in ra thông báo thân thiện, và tiếp tục chạy dòng lệnh cuối cùng.

Xử lý Ngoại lệ (try-catch-finally) - 0

3. Khối `finally`: Luôn luôn được thực thi

Đôi khi, có những hành động mà bạn muốn nó **luôn luôn** được thực thi. Bất kể có lỗi xảy ra hay không. Ví dụ như đóng một file, giải phóng tài nguyên, hoặc ngắt kết nối CSDL. Khối finally được sinh ra cho mục đích này. Nó được đặt sau khối `try-catch` và sẽ luôn được chạy cuối cùng.


import java.util.Scanner;

public class FinallyExample {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        try {
            System.out.print("Nhập một số: ");
            int number = scanner.nextInt();
            System.out.println("Bạn đã nhập số: " + number);
        } catch (Exception e) {
            System.out.println("Lỗi: Dữ liệu nhập vào không phải là số.");
        } finally {
            // Khối này luôn được chạy, dù có lỗi hay không
            System.out.println("Hành động trong finally luôn được thực hiện.");
            scanner.close(); // Đóng Scanner để giải phóng tài nguyên là một thói quen tốt
        }
    }
}

4. Từ khóa `throw`: Tự ném ra Ngoại lệ

Không chỉ Java mới có thể ném ra ngoại lệ. Chính bạn cũng có thể làm điều đó. Từ khóa throw cho phép bạn chủ động tạo và ném ra một đối tượng exception. Điều này rất hữu ích khi bạn muốn báo hiệu một lỗi nghiệp vụ. Ví dụ, một phương thức rút tiền có thể ném ra một exception nếu số dư không đủ.


public class ThrowExample {
    public static void checkAge(int age) {
        if (age < 18) {
            // Tự ném ra một ngoại lệ nếu tuổi không hợp lệ
            throw new IllegalArgumentException("Tuổi phải lớn hơn hoặc bằng 18.");
        } else {
            System.out.println("Tuổi hợp lệ, cho phép truy cập.");
        }
    }

    public static void main(String[] args) {
        try {
            checkAge(15);
        } catch (IllegalArgumentException e) {
            System.out.println("Đã bắt được lỗi: " + e.getMessage());
        }
    }
}

5. `Checked` vs. `Unchecked` Exceptions

Trong Java, ngoại lệ được chia thành hai loại chính:

  • Checked Exceptions: Đây là các lỗi mà trình biên dịch **bắt buộc** bạn phải xử lý (bằng `try-catch` hoặc khai báo `throws`). Chúng thường là các lỗi liên quan đến các yếu tố bên ngoài mà chương trình không kiểm soát được. Ví dụ: `IOException` (lỗi đọc/ghi file), `SQLException` (lỗi CSDL).
  • Unchecked Exceptions (Runtime Exceptions): Đây là các lỗi mà bạn **không bị bắt buộc** phải xử lý. Chúng thường là các lỗi logic trong code. Ví dụ: `NullPointerException` (truy cập đối tượng null), `ArithmeticException` (lỗi toán học), `ArrayIndexOutOfBoundsException` (truy cập chỉ số mảng không tồn tại).

Kết luận

Xử lý ngoại lệ là một kỹ năng không thể thiếu. Nó giúp chương trình của bạn trở nên ổn định và thân thiện với người dùng. Bằng cách sử dụng `try-catch-finally`, bạn có thể kiểm soát các tình huống lỗi một cách chủ động. Điều này giúp ngăn chặn các sự cố không đáng có. Ở bài tiếp theo, chúng ta sẽ học cách làm việc với file. Bạn sẽ biết cách đọc và ghi dữ liệu ra các file văn bản trên máy tính.

0 Bình luận