Ngoại lệ và cách xử lý ngoại lệ trong Java

12 tháng 02, 2022 - 10764 lượt xem

image

Hãy tưởng tượng vào một ngày đẹp trời, bạn quyết định tự lái xe từ Hà Nội đến Bắc Ninh để xem Spider-Man: No way home do Hà Nội chưa mở rạp chiếu phim. Tuy nhiên đang đi giữa đường thì bất ngờ xe của bạn bị thủng lốp. Sự kiện bất ngờ và không mong muốn này chính là ngoại lệ (exception)

Tương tự, khi chúng ta tạo một chương trình Java và nó được biên dịch thành công, các ngoại lệ vẫn có thể xảy ra, phá vỡ luồng bình thường của một chương trình, thậm chí là chết chương trình.

Trong bài viết này chúng ta sẽ cùng tìm hiểu ngoại lệ là gì và cách để xử lý chúng.

Ngoại lệ là gì?

Ngoại lệ có nghĩa là một vấn đề hoặc một tình trạng bất thường khiến chương trình máy tính ngừng xử lý thông tin theo cách bình thường.

Ngoại lệ trong Java là một đối tượng đại diện cho một lỗi hoặc một sự kiện bất ngờ xảy ra khi chương trình chạy và làm gián đoạn luồng thực thi bình thường của chương trình.

Ví dụ: Khi chúng ta thực hiện chia một số cho 0 sẽ dẫn tới xảy ra ngoại lệ ArithmeticException. Hay khi cần nhập chiều cao và cân nặng để tính bmi, nhưng người dùng lại nhập chữ, cũng sẽ xảy ra ngoại lệ.

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

  • Người dùng nhập dữ liệu không hợp lệ
  • Không tìm thấy file để đọc
  • Mất kết nối mạng,…

Hệ thống phân cấp của Exception

Lớp java.lang.Throwable là lớp gốc của hệ thống phân cấp ngoại lệ. Nó được kế thừa bởi 2 lớp con là Exception và Error. Xem hình dưới đây:

image

Các loại Exception trong Java

Chủ yếu có 2 loại ngoại lệ: checked và unchecked. Mỗi error được coi là unchecked exception. Tuy nhiên, theo Oracle, có ba loại exception:

  • Checked Exception: Là loại exception xảy ra trong lúc compile time. Có thể kể đến như: IOException, SQLException,…
  • Unchecked Exception: Các ngoại lệ không được kiểm tra tại thời điểm biên dịch, nhưng được kiểm tra trong thời gian chạy. Ví dụ như: ArithmeticException, NullPointerException, …
  • Error: Không thể khôi phục được. Như: OutOfMemoryError, VirtualMachineError,…

Một số ngoại lệ phổ biến có thể xảy ra

Khi chia một số cho 0

int number = 9;
int zero = 0;
int result = number/zero;  //ArithmeticException

Thao tác với chuỗi rỗng

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

Lỗi khi ép kiểu

String str = "Chuỗi";
int number = Integer.parseInt(str); //NumberFormatException

Thêm phần tử sai index trong mảng

int []arr = new int[5];
arr[10] = 7; //ArrayIndexOutOfBoundsException

Kích thước mảng là số âm

int[] arr = new int[-5]; //NegativeArraySizeException

Xử lý ngoại lệ

Java cung cấp 5 từ khóa sử dụng để xử lý ngoại lệ đó là:

Từ khóaMô tả
trySử dụng để chứa đoạn lệnh có thể gây ra ngoại lệ, nó phải được theo sau bởi khối catch hoặc finally
catchSử dụng để xử lý ngoại lệ, các khối code để xử lý ngoại lệ sẽ được đặt trong đây
finallySử dụng để thực thi đoạn mã cần thiết của chương trình. Khối này sẽ luôn được thực thi
throwSử dụng để ném ra ngoại lệ
throwsSử dụng để khai báo ngoại lệ

1, Khối lệnh try-catch

Cú pháp:

try{
    //Khối lệnh có thể ném ra ngoại lệ
}catch(<Exception_class_name> e){
    //Code xử lý ngoại lệ
}

Ví dụ: Mình sẽ thử xử lý với trường hợp chia một số cho 0

try{
    int number = 9;
    int zero = 0;
    int result = number/zero;  //ArithmeticException
    System.out.println(result);
}catch (ArithmeticException e){
    System.out.println(e.toString());
}

Kết quả:

java.lang.ArithmeticException: / by zero

2, Khối try-finally

Cú pháp:

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

3, Khối try-catch-finally

Cú pháp:

try{
    //Khối lệnh có thể ném ra ngoại lệ
}catch(<Exception_class_name_1> e){
    //Code xử lý ngoại lệ 1
}catch(<Exception_class_name_2> e){
    //Code xử lý ngoại lệ 2
}finally{
    //Khối lệnh trong đây luôn được thực thi
}

4, Từ khóa throw

Từ khóa throw được sử dụng để ném ra ngoại lệ cụ thể. Thông thường nó được sử dụng với exception do người dùng tự định nghĩa

Ví dụ:

System.out.println("Nhập tuổi của bạn:");
age = sc.nextInt();
//Tuổi không hợp lệ khi nhập số âm hoặc lớn hơn 200
if(age < 0 || age > 200)
    throw new ArithmeticException("Tuổi không hợp lệ");

5, Từ khóa throws

Từ khóa throws sử dụng để khai báo ngoại lệ. Nó được sử dụng chủ yếu với checked exception

Ví dụ:

public void readFile() throws IOException{ // Khai báo ngoại lệ

}

Custom Exception

Custom exception là ngoại lệ do người dùng tự định nghĩa, được sử dụng để tùy biến ngoại lệ theo yêu cầu của người dùng.

Để tạo custom exception thuộc loại checked chúng ta kế thừa từ lớp Exception, còn với unchecked exception thì kế thừa từ lớp RuntimeException

Ví dụ: Tạo custom exception loại checked

public class MyException extends Exception{
    public MyException(String message) {
        super(message);
    }
}

Ví dụ xử lý ngoại lệ

Ví dụ: Viết chương trình nhập tuổi từ bàn phím, kiểm tra đã đủ tuổi bầu cử chưa.

Tuy nhiên khi thực hiện nhập dữ liệu vào từ bàn phím, có thể xảy ra trường hợp nhập chữ, hoặc tuổi là một số âm hoặc nhâp tuổi quá lớn. Do đó mình sẽ xử lý ngoại lệ với 3 trường hợp trên.

public class Main {

    public static void main(String[] args) {
        int age = getAge();
        if(age >= 18){
            System.out.println("Bạn đã đủ tuổi bầu cử");
        }else{
            System.out.println("Từ từ rồi sẽ đủ tuổi");
        }

    }

    public static int getAge(){
        Scanner sc = new Scanner(System.in);
        int age = 0;

        boolean isContinue = true;

        while(isContinue){ //Sử dụng vòng lặp để mỗi khi nhập sai sẽ yêu cầu nhập lại cho đến khi đúng
            try {
                System.out.println("Nhập tuổi của bạn:");
                age = Integer.parseInt(sc.nextLine());
                //Tuổi không hợp lệ khi nhập số âm hoặc lớn hơn 200
                if(age < 0 || age > 200)
                    throw new ArithmeticException("Tuổi không hợp lệ"); //sử dụng throw để ném ra ngoại lệ
                isContinue = false;  //gán lại isContinue để dùng vòng lặp
            }catch (NumberFormatException e){ //Do có hai ngoại lệ có thể sảy ra nên sử dụng 2 khối catch để xử lý
                System.out.println("Tuổi phải là số");
            }catch (ArithmeticException e){
                System.out.println(e.getMessage());
            }
        }
        return age;
    }
}

Khóa học Java Fullstack cho người mới bắt đầu - tại đây
Liên hệ tư vấn - ms Mẫn 0963023185 (zalo)

Bình luận

avatar
Nguyễn Xuân Trường 2022-02-24 13:52:01.361005 +0000 UTC

hay quá cô

Avatar
* Vui lòng trước khi bình luận.
Ảnh đại diện
  +3 Thích
+3