BÀI 2: CÁC THÀNH PHẦN CO BẢN TRONG JAVA
5.6. Xử lý ngoại lệ - Exception
Ngoại lệ (Exception) là các lỗi phát sinh trong khi chạy chương trình. Theo cách truyền thống, chúng ta dùng các giá trị trạng thái kết quả xử lý hoặc các biến toàn cục, khi đó người lập trình kiểm soát bằng cách kiểm tra các giá trị này để biết
có lỗi hay không và xử lý tương ứng. Tuy nhiên hiện nay, các ngôn ngữ lập trình hiện đại cung cấp cơ chế xử lý các lỗi thuận tiện và đồng bộ hơn đó là cơ chế ngoại
lệ.
Các ngoại lệ được chia làm nhiều loại theo nhóm lỗi tương ứng gồm:
Ngoại lệ Các lỗi tương ứng
Exception Bao hàm tất cả các lỗi
IOException Lỗi vào/ra dữ liệu
NumberFormatException Lỗi định dạng dữ liệu số
OutOfMemoryException Lỗi tràn bộ nhớ
NullPointerException Lỗi tham chiếu có giá trị null
IllegalArgumentException Lỗi sai tham số truyền cho hàm ArithmeticException Lỗi tính toán toán học
ArrayIndexOutOfBoundsException Lỗi xử lý mảng ngoài chỉ số,...
Thông thường để đơn giản chúng ta dùng Exception để bao hàm tất cả các lỗi nếu có. Sử dụng cú pháp sau để xử lý lỗi phát sinh trong chương trình.
try{
/*Đoạn mã chương trình cần kiểm tra lỗi*/
}catch(ExceptionType1 e1){
/* Xử lý lỗi thứ 1*/
}catch(ExceptionType2 e2){
/* Xử lý lỗi thứ 2*/
}catch(ExceptionType3 e3){
/*Xử lý lỗi thứ 3*/
}...
finally{
/*Xử lý cuối cùng*/
}
Trong đó phần “catch” cần tối thiểu là một lỗi cho khối “try” và có thể bỏ qua
“finally”. Đoạn mã chương trình cần kiểm tra lỗi có thể do chúng ta mong muốn vì
sợ rằng khi chạy có thể sinh lỗi, tuy nhiên một số lệnh trong Java khi chạy nếu có lỗi sẽ chủ động phát sinh và bắt buộc chúng ta xử lý như trên. “ExceptionType” trong “catch” là một trong các kiểu ngoại lệ tương ứng với lỗi cần kiểm tra xử lý trong bảng trên.
Khi máy tính thực hiện đoạn chương trình theo cú pháp trên, trước hết sẽ thực thi đoạn mã nằm trong khối “try”. Nếu phát sinh lỗi ngay lập tức tìm kiếm lỗi đó có nằm trong danh sách kiểu lỗi trong các khối “catch”, nếu tìm thấy ở đâu sẽ xử lý bằng cách chạy đoạn mã tương ứng. Ngược lại, nếu không tìm thấy sẽ ngắt chương trình và đưa ra màn hình Console thông báo lỗi. Khối “finally” luôn luôn được thực hiện cho dù đoạn mã trong khối “try” có chạy thành công hay không.
Như vậy nếu không bắt hết các kiểu ngoại lệ thì nguy cơ chương trình bị ngắt trong quá trình thực là có thực. Để đơn giản, chúng ta sử dụng kiểu “Exception” để bao hàm hầu hết các lỗi và xử lý trong chương trình. Ví dụ sau sẽ nhập một chuỗi
ký tự, và chuyển nó thành số nguyên (nếu được) đưa ra thông báo kết quả. Nếu không sẽ đưa ra thông báo lỗi và tiếp tục chạy chương trình.
try{
Scanner n = new Scanner(System.in);
System.out.print("Nhap xau ky tu: ");
String s = n.nextLine();
int a = Integer.parseInt(s);
System.out.printf("\nKET QUA CHUYEN: %d\n",a);
}catch(Exception e){
System.out.print("\nWRONG NUMBER\n");
}finally{
System.out.print("\nFINALLY\n");
}
System.out.print("\nCONTINUE\n");
Kết quả chạy chương trình trong cả 2 trường hợp nhập đúng và không đúng số nguyên.
và
Tuy nhiên nếu chúng ta sử dụng kiểu ngoại lệ không phù hợp và máy không tìm thấy thì chương trình sẽ bị ngắt, chẳng hạn đổi kiểu ngoại lệ trong khối “catch” của ví dụ trên thành “IllegalStateException” sẽ cho kết quả khi nhập sai là,
và sẽ không chạy tiếp các lệnh sau khối “try-catch-finally”, chương trình bị ngắt giữa chừng.
Trường hợp chúng ta muốn kiểm soát lỗi nhưng không sử dụng khối “try- catch-finally” sẽ thay thế bằng việc sử dụng mệnh đề “throws” ngay sau tên phương thức (hàm) chứa khối lệnh này. Ví dụ như sau:
void Test() throws Exception{
Scanner n = new Scanner(System.in);
System.out.print("Nhap xau ky tu: ");
String s = n.nextLine();
int a = Integer.parseInt(s);
System.out.printf("\nKET QUA CHUYEN: %d\n",a);
}
Như vậy tại nơi gọi hàm “Test” này sẽ phải thực hiện xử lý ngoại lệ bằng cú pháp “try-catch-finally” như trên hoặc tiếp tục áp dụng mệnh đề “throws” như trên... Nếu quá trình áp dụng mệnh đề “throws” ở tất cả các phương thức (hàm) thì cuối cùng các ngoại lệ sẽ đưa đến hàm “main” của chương trình.
Tuy nhiên, khi áp dụng mệnh đề “throws” thì máy sẽ ngắt quá trình thực hiện của phương thức tương ứng nếu gặp lỗi, tức là toàn bộ nội dung của phương thức được coi như là đoạn mã cần kiểm tra xử lý lỗi (nằm trong khối “try”), cho dù chúng ta mong muốn phương thức đó vẫn được tiếp tục chạy và bỏ qua lỗi.