Xử lý ngoại lệ trong Java (Exception Handling) – GP Coder (Lập trình Java)

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

Exception là một sự kiện xảy ra trong quá trình thực thi một chương trình Java, nó làm phá vỡ cái flow (luồng xử lý) bình thường của một chương trình, thậm chí chết chương trình.

Một ngoại lệ hoàn toàn có thể xảy ra với nhiều nguyên do khác nhau, nó nằm ngoài dự trù của chương trình. Một vài ngoại lệ xảy ra bởi lỗi của người dùng, 1 số ít khác bởi lỗi của lập trình viên và số khác nữa đến từ lỗi của nguồn tài liệu vật lý. Chẳng hạn như :

  • Người dùng nhập dữ liệu không hợp lệ.
  • Truy cập ngoài chỉ số mảng.
  • Một file cần được mở nhưng không thể tìm thấy.
  • Kết nối mạng bị ngắt trong quá trình thực hiện giao tiếp hoặc JVM hết bộ nhớ.
  • ….

Ví dụ chương trình chia 2 số. Nếu ta cho mẫu số = 0 thì phát sinh lỗi và đó được coi là 1 ngoại lệ .


public class ExceptionExample1 {

	public static void main(String[] args) {

		int zero = 0;

		int average = 10 / zero;

		System.out.println("Average = " + average);

	}

}

Khi thực thi chương trên, sẽ nhận được thông báo lỗi như sau:

Exception in thread "main" java.lang.ArithmeticException: / by zero

Hệ thống cấp bậc của các lớp ngoại lệ trong Java

Đây là mô hình sơ đồ phân cấp của Exception trong java.

  • Class ở mức cao nhất là Throwable
  • Hai class con trực tiếp là Error và Exception.

Trong nhánh Exception có một nhánh con RuntimeException là các ngoại lệ sẽ không được java kiểm tra trong thời điểm biên dịch.Ý nghĩa của được kiểm tra và không được kiểm tra tại thời điểm biên dịch sẽ được minh họa trong các ví dụ phần sau.

Exception

Trong Java có 2 loại exception : checked và unchecked. Tất cả các checked exception được thừa kế từ lớp Exception ngoại trừ lớp RuntimeException. RuntimeException là lớp cơ sở của toàn bộ các lớp unchecked exception. Đó cũng là tín hiệu để nhận biết đâu là checked exception và đâu là unchecked exception .Điểm độc lạ giữa các lớp checked và unchecked expcetion chính là thời gian xác lập được expcetion hoàn toàn có thể xảy ra .

Checked exceptions

Là loại exception xảy ra trong lúc compile time, nó cũng có thể được gọi là compile time exceptions. Loại exception này không thể bỏ qua được trong quá trình compile, bắt buộc ta phải handle nó.

Các lớp extends từ lớp Throwable ngoại trừ RuntimeException và Error được gọi là checked exception .Ví dụ : IOException, FileNotFoundException, NoSuchFieldException, … .Ví dụ chương trình sau đọc file sử dụng java.io. FileReader lớp này ném ra ngoại lệ FileNotFoundException. Trình biên dịch thông tin lỗi như sau :

UnChecked exceptions

Là loại exception xảy ra tại thời điểm thực thi chương trình, nó cũng có thể gọi là runtime exceptions đó là programming bugs, lỗi logic của chương trình… Loại exception này được bỏ qua trong quá trình compile, không bắt buộc ta phải handle nó.

Các lớp extends từ RuntimeException được gọi là unchecked exception .Ví dụ : NullPointerException, NumberFormatException, ArrayIndexOutOfBoundsException, DivideByZeroException, …Ví dụ một biến có giá trị null, thực thi bất kể hoạt động giải trí nào bởi biến đó sẽ xảy ra ngoại lệ NullPointerException .

Error

Error là những yếu tố nghiêm trọng tương quan đến môi trường tự nhiên thực thi của ứng dụng hoặc mạng lưới hệ thống mà lập trình viên không hề trấn áp. Nó thường làm chết chương trình .Lớp Error định nghĩa các ngoại lệ mà không hề bắt ( catch ) từ chương trình .Ví dụ : OutOfMemoryError, VirtualMachineError, and StackOverflowError, …Ví dụ chương trình đệ quy vô tận :

Các ngữ cảnh thông dụng nơi ngoại lệ hoàn toàn có thể xảy ra

ArithmeticException

Nếu tất cả chúng ta chia bất kể số nào cho số 0, xảy ra ngoại lệ ArithmeticException .Ví dụ :


int a = 10 / 0; // ArithmeticException

NullPointerException

Nếu một bất kỳ biến nào có giá trị null, thực hiện bất kỳ hoạt động nào bởi biến đó sẽ xảy ra ngoại lệ NullPointerException.

Ví dụ :


String obj = null;
System.out.println(obj .length()); // NullPointerException

NumberFormatException

Một biến String có giá trị là các ký tự, quy đổi biến này thành số sẽ xảy ra NumberFormatException .


String str = "abc"; 
int num = Integer.parseInt(str); // NumberFormatException 

ArrayIndexOutOfBoundsException

Nếu bạn chèn bất kể giá trị nào vào index sai, sẽ xảy ra ngoại lệ ArrayIndexOutOfBoundsException .


int arr[] = new int[5];
arr[5] = 50; // ArrayIndexOutOfBoundsException

ClassCastException

Nếu không hề chuyển kiểu object này sang kiểu object khác, sẽ xảy ra ngoại lệ ClassCastException .


Object dog = new Dog();
Rectangle rect = (Rectangle) dog;

Xử lý ngoại lệ (Exception Handling) trong java

Xử lý ngoại lệ là gì ?

Xử lý ngoại lệ ( Exception Handling ) trong java là một chính sách giải quyết và xử lý các lỗi runtime để hoàn toàn có thể duy trì luồng thông thường của ứng dụng .Quá trình giải quyết và xử lý exception được gọi là catch exception, nếu Runtime System không giải quyết và xử lý được ngoại lệ thì chương trình sẽ kết thúc .

JVM xử lý Exceptions thế nào

Khi một lỗi xảy ra trên một method, method đó sẽ tạo ra một object và đưa nó vào Runtime System. Object đó được gọi là Exception Object, nó chứa tất cả các thông tin về lỗi và trạng thái của chương trình khi xảy ra lỗi.

Sau đó, Runtime System sẽ giải quyết và xử lý sẽ tìm cách giải quyết và xử lý ngoại lệ tương thích được sử dụng tại method ấy. Nếu không có thì JVM liên tục tìm giải quyết và xử lý ngoại lệ tương thích ở các method trên ( là method gọi lớp hiện tại ). Nếu không có method nào có giải quyết và xử lý ngoại lệ tương thích thì Thread mà đang thực thi chuỗi method xảy ra ngoại lệ bị ngắt. Nếu thread ấy là thread main thì chết chương trình .

Cú pháp giải quyết và xử lý ngoại lệ trong Java

Khối lệnh try trong java được sử dụng để chứa một đoạn code có thế xảy ra một ngoại lệ. Nó phải được khai báo trong phương pháp .Sau một khối lệnh try bạn phải khai báo khối lệnh catch hoặc finally hoặc cả hai .

Cú pháp của khối lệnh try-catch


try {
	// code có thể ném ra ngoại lệ
} catch(Exception_class_Name ex) {
	// code xử lý ngoại lệ
}

Cú pháp của khối lệnh try-finally

try {
// code có thể ném ra ngoại lệ
} finally {
// code trong khối này luôn được thực thi
}

Cú pháp của khối lệnh try-catch-finally


try {
	// code có thể ném ra ngoại lệ
} catch(Exception_class_Name_1 ex) {
	// code xử lý ngoại lệ 1
} catch(Exception_class_Name_2 ex) {
	// code xử lý ngoại lệ 2
} catch(Exception_class_Name_n ex) {
	// code xử lý ngoại lệ n
} finally {
	// code trong khối này luôn được thực thi
}

Các phương pháp của lớp Exception

STT Phương thức và Miêu tả
1 public String getMessage()
Trả về một message cụ thể về exception đã xảy ra. Message này được khởi tạo bởi phương thức contructor của Throwable
2 public Throwable getCause()
Trả về nguyên nhân xảy ra exception biểu diễn bởi đối tượng Throwable
3 public String toString()
Trả về tên của lớp và kết hợp với kết quả từ phương thức getMessage()
4 public void printStackTrace()
In ra kết quả của phương thức toString cùng với stack trace đến System.err
5 public StackTraceElement [] getStackTrace()
Trả về một mảng chứa mỗi phần tử trên stack trace. Phần tử tại chỉ mục 0 biểu diễn phần trên cùng của Call Stack, và phần tử cuối cùng trong mảng biểu diễn phương thức tại dưới cùng của Call Stack
6 public Throwable fillInStackTrace()
Fills the stack trace of this Throwable object with the current stack trace, adding to any previous information in the stack trace.

Các ví dụ minh họa việc giải quyết và xử lý ngoại lệ

Ví dụ xử lý ngoại lệ thực hiện phép chia cho số 0

Khi chưa giải quyết và xử lý ngoại lệ


public class ExceptionExample1 {

	public static void main(String[] args) {
		int zero = 0;
		int average = 10 / zero;
		System.out.println("Average = " + average);
		System.out.println("Finished!");
	}

}

Thực thi chương trình trên :

Exception in thread "main" java.lang.ArithmeticException: / by zero
	at com.gpcoder.exception.ExceptionExample1.main(ExceptionExample1.java:7)

Xử lý ngoại lệ ArithmeticException cho chương trình trên

public class ExceptionExample1 {

	public static void main(String[] args) {
		try {
			int zero = 0;
			int average = 10 / zero;
			System.out.println("Average = " + average);
		} catch (ArithmeticException ex) {
			System.out.println(ex);
		}
		System.out.println("Finished!");
	}

}

Kết quả thực thi chương trình trên :

java.lang.ArithmeticException: / by zero
Finished!

Ví dụ về khối lệnh try lồng nhau


public class ExceptionExample1 {

	public static void main(String[] args) {
		try {
			try {
				int zero = 0;
				int average = 10 / zero;
				System.out.println("Average = " + average);
			} catch (ArithmeticException ex) {
				System.out.println(ex);
			}

			System.out.println("Continue...");
			int arr[] = new int[5];
			arr[5] = 4;
			System.out.println("arr[5] = " + arr[5]);

		} catch (ArrayIndexOutOfBoundsException ex) {
			System.out.println(ex);
		}

		System.out.println("Finished!");
	}

}

Kết quả thực thi chương trình trên :

java.lang.ArithmeticException: / by zero
Continue...
java.lang.ArrayIndexOutOfBoundsException: 5
Finished!

Ví dụ sau sử dụng nhiều khối lệnh catch

public class ExceptionExample1 {

	public static void main(String[] args) {
		try {
			int arr[] = new int[5];
			arr[5] = 4;
			System.out.println("arr[5] = " + arr[5]);
			
			int zero = 0;
			int average = 10 / zero;
			System.out.println("Average = " + average);
			
			String obj = null;
			System.out.println(obj.length());
		} catch (NullPointerException ex) {
			System.out.println(ex);
		} catch (ArithmeticException ex) {
			System.out.println(ex);
		} catch (ArrayIndexOutOfBoundsException ex) {
			System.out.println(ex);
		}

		System.out.println("Finished!");
	}

}

Kết quả thực thi chương trình trên :

java.lang.ArrayIndexOutOfBoundsException: 5
Finished!

Ví dụ sử dụng khối lệnh finally nơi ngoại lệ không xảy ra

public class ExceptionExample1 {

	public static void main(String[] args) {
		try {
			int res = 10/2;
			System.out.println("10/2 = " + res);
		} finally {
			System.out.println("Khối lệnh finally luôn được thực thi");
		}

		System.out.println("Finished!");
	}

}

Kết quả thực thi chương trình trên :

10/2 = 5
Khối lệnh finally luôn được thực thi
Finished!

Ví dụ sử dụng khối lệnh finally nơi ngoại lệ xảy ra nhưng không giải quyết và xử lý

public class ExceptionExample1 {

	public static void main(String[] args) {
		try {
			int arr[] = new int[5];
			arr[5] = 4;
			System.out.println("arr[5] = " + arr[5]);
		} catch (NullPointerException ex) {
			System.out.println(ex);
		} finally {
			System.out.println("Khối lệnh finally luôn được thực thi");
		}

		System.out.println("Finished!");
	}

}

Kết quả thực thi chương trình trên :

Khối lệnh finally luôn được thực thiException in thread "main" 
java.lang.ArrayIndexOutOfBoundsException: 5
	at com.gpcoder.exception.ExceptionExample1.main(ExceptionExample1.java:8)

Ví dụ sử dụng khối lệnh finally nơi ngoại lệ xảy ra và được giải quyết và xử lý

public class ExceptionExample1 {

	public static void main(String[] args) {
		try {
			int arr[] = new int[5];
			arr[5] = 4;
			System.out.println("arr[5] = " + arr[5]);
		} catch (NullPointerException ex) {
			System.out.println(ex);
		} catch (ArrayIndexOutOfBoundsException ex) {
			System.out.println(ex);
		} finally {
			System.out.println("Khối lệnh finally luôn được thực thi");
		}

		System.out.println("Finished!");
	}

}

Kết quả thực thi chương trình trên :

java.lang.ArrayIndexOutOfBoundsException: 5
Khối lệnh finally luôn được thực thi
Finished!

Một số quan tâm

  • Tại một thời điểm chỉ xảy ra một ngoại lệ và tại một thời điểm chỉ có một khối catch được thực thi. Khi exception đã bị bắt ở một catch thì các catch tiếp theo sẽ không được bắt.
  • Tất cả các khối catch phải được sắp xếp từ cụ thể nhất đến chung nhất (từ exception con đến exception cha), tức là phải khai báo khối lệnh catch để xử lý lỗi NullPointerException, ArithmeticException, … trước khi khai báo catch để xử lý lỗi Exception.
  • Khối lệnh finally luôn được thực thi dù chương trình có xảy ra ngoại lệ hay không (ngay cả sử dụng lệnh return).
  • Đối với mỗi khối try, có thể không có hoặc nhiều khối catch, nhưng chỉ có một khối finally.
  • Khối finally sẽ không được thực thi nếu chương trình bị thoát bằng cách gọi System.exit() hoặc xảy ra một lỗi (Error) không thể tránh khiến chương trình bị chết.

Ví dụ sử dụng System. exit ( ) để không thực thi khối lệnh finally


public class ExceptionExample1 {

	public static void main(String[] args) {
		try {
			int arr[] = new int[5];
			arr[5] = 4;
			System.out.println("arr[5] = " + arr[5]);
		} catch (ArrayIndexOutOfBoundsException ex) {
			System.out.println(ex);
			System.exit(0); // Khối finally sẽ không được thực thi
		} finally {
			System.out.println("Khối lệnh finally luôn được thực thi");
		}

		System.out.println("Finished!");
	}

}

Kết quả thực thi chương trình trên :

java.lang.ArrayIndexOutOfBoundsException: 5

Ví dụ khối finally vẫn được thực thi dù gọi lệnh return


public class ExceptionExample1 {
	
	public static int getValueAtIndex5() {
		try {
			int arr[] = new int[5];
			arr[5] = 4;
			System.out.println("arr[5] = " + arr[5]);
			return 1;
		} catch (ArrayIndexOutOfBoundsException ex) {
			System.out.println(ex);
			return 0; // Return kết quả nhưng vẫn thực thi khối finally
		} finally {
			System.out.println("Khối lệnh finally luôn được thực thi");
		}
	}

	public static void main(String[] args) {
		System.out.println("getValueAtIndex5() = " + getValueAtIndex5());
	}

}

Kết quả thực thi chương trình trên :

java.lang.ArrayIndexOutOfBoundsException: 5
Khối lệnh finally luôn được thực thi
getValueAtIndex5() = 0

Tài liệu tham khảo:

Trên đây là những hướng dẫn cơ bản về giải quyết và xử lý ngoại lệ ( exception handling ). Hy vọng giúp ích cho các bạn, hẹn gặp lại các bạn ở những bài viết tiếp theo .4.7

Nếu bạn thấy hay thì hãy chia sẻ bài viết cho mọi người nhé!

Shares

Bình luận

phản hồi