1. Tại sao cần try-catch?
Như bạn đã biết, trong lập trình lỗi xảy ra liên tục: chia cho 0, nhập sai, thiếu tệp, v.v. Nếu không xử lý những tình huống như vậy, chương trình sẽ kết thúc với lỗi (sập).
Cấu trúc try-catch cho phép “bắt” ngoại lệ và ngăn chương trình sập, xử lý lỗi một cách an toàn.
Cú pháp của cấu trúc try-catch
try
{
// Mã có thể ném ngoại lệ
}
catch (TipIsklyucheniya imyaPeremennoy)
{
// Mã để xử lý ngoại lệ
}
Giải thích:
- try — “hãy thử thực thi đoạn mã này”.
- catch — “nếu xuất hiện ngoại lệ thuộc kiểu chỉ định, hãy xử lý nó ở đây”.
Nó hoạt động như thế nào?
Nếu trong khối try xảy ra ngoại lệ, việc thực thi khối này lập tức bị dừng và quyền điều khiển chuyển sang khối catch phù hợp đầu tiên. Nếu không có ngoại lệ — khối catch sẽ bị bỏ qua.
2. Ví dụ: chia cho 0
Không xử lý ngoại lệ
int a = 10;
int b = 0;
int result = a / b; // Ở đây chương trình sẽ kết thúc với lỗi!
System.out.println("Kết quả: " + result); // Chúng ta sẽ không tới được dòng này
Kết quả:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Main.main(Main.java:3)
Có xử lý bằng try-catch
int a = 10;
int b = 0;
try
{
int result = a / b; // Ở đây có thể phát sinh ngoại lệ
System.out.println("Kết quả: " + result);
}
catch (ArithmeticException e)
{
System.out.println("Lỗi: không thể chia cho 0!");
}
System.out.println("Chương trình đã tiếp tục chạy.");
Kết quả:
Lỗi: không thể chia cho 0!
Chương trình đã tiếp tục chạy.
Giải thích:
- Ngay khi Java gặp phép chia cho 0, nó “ném” một ngoại lệ.
- try bị dừng, và quyền điều khiển chuyển sang catch.
- Sau khi xử lý lỗi, chương trình tiếp tục thực thi.
3. Cách khối catch hoạt động
Trong dấu ngoặc sau catch chỉ ra kiểu ngoại lệ (ví dụ, ArithmeticException) và tên biến (thường là e).
Bên trong khối catch có thể biết chi tiết về lỗi:
- e.getMessage() — mô tả ngắn gọn về lỗi.
- e.printStackTrace() — thông tin chi tiết (dùng cho gỡ lỗi).
Ví dụ:
try
{
int[] arr = new int[2];
int x = arr[10]; // Lỗi: chỉ số không tồn tại
}
catch (ArrayIndexOutOfBoundsException e)
{
System.out.println("Lỗi: " + e.getMessage()); // In thông báo lỗi
e.printStackTrace(); // In toàn bộ thông tin lỗi ra console
}
4. Luồng thực thi khi có ngoại lệ
Nếu trong khối try không có lỗi — khối catch sẽ bị bỏ qua.
Nếu trong khối try xảy ra lỗi — việc thực thi khối bị dừng tại vị trí lỗi, và quyền điều khiển lập tức chuyển sang catch phù hợp đầu tiên. Mọi thứ sau vị trí lỗi trong try sẽ không được thực thi!
Minh họa:
try
{
System.out.println("1. Bắt đầu try");
int a = 10 / 0; // Lỗi!
System.out.println("2. Sau phép chia"); // Sẽ không được thực thi
}
catch (ArithmeticException e)
{
System.out.println("3. Trong khối catch");
}
System.out.println("4. Sau try-catch");
Kết quả:
1. Bắt đầu try
3. Trong khối catch
4. Sau try-catch
5. Lỗi thường gặp khi sử dụng try-catch
Lỗi số 1: catch quá rộng.
Nếu dùng catch (Exception e), bạn có thể bắt rất nhiều lỗi không mong đợi mà bạn không xử lý đúng cách.
Giải pháp: chỉ bắt những ngoại lệ thực sự được dự kiến tại vị trí này (ví dụ, IOException, SQLException).
Lỗi số 2: catch rỗng.
Viết catch (Exception e) {} — tức là che giấu vấn đề. Chương trình sẽ sập ở chỗ khác hoặc hành xử kỳ lạ.
Giải pháp: ít nhất hãy ghi log lỗi (e.printStackTrace() hoặc logger).
Lỗi số 3: Tin rằng try-catch sẽ sửa mọi vấn đề.
Nếu lỗi nằm ở logic chương trình (ví dụ, chia cho 0, thuật toán sai) — thì không try-catch nào giúp được.
Giải pháp: hãy dùng try-catch chỉ cho các tình huống thật sự được dự kiến, không phải để che giấu bug.
GO TO FULL VERSION