JavaRush /Blog Java /Random-VI /Các ngoại lệ trong Java (Ngoại lệ Java)

Các ngoại lệ trong Java (Ngoại lệ Java)

Xuất bản trong nhóm
Trong cuộc sống hàng ngày, đôi khi có những tình huống xảy ra mà chúng ta không lường trước được. Ví dụ, bạn thức dậy đi làm vào buổi sáng, tìm bộ sạc cho điện thoại nhưng không có. Bạn vào phòng tắm rửa mặt - nước đã tắt. Tôi bước vào xe và nó không khởi động được. Nhưng một người có thể đối phó với những tình huống không lường trước được như vậy khá dễ dàng. Chúng ta sẽ cố gắng tìm hiểu cách các chương trình Java xử lý chúng trong bài viết này.

Ngoại lệ java là gì

Trong thế giới lập trình, việc xảy ra lỗi và các tình huống không mong muốn trong quá trình thực thi chương trình được gọi là ngoại lệ. Trong một chương trình, các trường hợp ngoại lệ có thể xảy ra do hành động không chính xác của người dùng, thiếu tài nguyên cần thiết trên đĩa hoặc mất kết nối với máy chủ qua mạng. Các ngoại lệ trong quá trình thực thi chương trình cũng có thể do lỗi lập trình hoặc sử dụng API không chính xác. Không giống như thế giới của chúng ta, chương trình phải biết rõ ràng phải làm gì trong tình huống như vậy. Java cung cấp một cơ chế ngoại lệ cho mục đích này.

Sơ lược về các từ khóa thử, bắt, cuối cùng, ném

Xử lý ngoại lệ trong Java dựa trên việc sử dụng các từ khóa sau trong chương trình:
  • thử - xác định một khối mã trong đó có thể xảy ra ngoại lệ;
  • bắt – xác định khối mã trong đó ngoại lệ được xử lý;
  • cuối cùng – xác định một khối mã là tùy chọn, nhưng nếu có, vẫn được thực thi, bất kể kết quả của khối thử.
Những từ khóa này được sử dụng để tạo các cấu trúc xử lý đặc biệt trong mã chương trình: thử{}bắt, thử{}bắt{}cuối cùng, thử{}cuối cùng{}.
  • ném – dùng để đưa ra một ngoại lệ;
  • ném - được sử dụng trong chữ ký phương thức để cảnh báo rằng phương thức đó có thể đưa ra một ngoại lệ.
Một ví dụ về sử dụng từ khóa trong chương trình Java:
//method reads a string from the keyboard

public String input() throws MyException {//warn with throws,
// that the method can throw MyException
      BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
    String s = null;
// in the try block we enclose the code in which an exception can occur, in this
// if the compiler tells us that the readLine() method of the class
// BufferedReader may throw an I/O exception
    try {
        s = reader.readLine();
// in the catch block we enclose the code for handling the IOException exception
    } catch (IOException e) {
        System.out.println(e.getMessage());
// close the read stream in the finally block
    } finally {
// when closing the stream, an exception is also possible, for example, if it was not opened, so we “wrap” the code in a try block
        try {
            reader.close();
// write exception handling when closing the read stream
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
    }

    if (s.equals("")) {
// we decided that an empty string could disrupt the work of our program in the future, for example, on the result of this method, we need to call the substring(1,2) method, so we are forced to interrupt the program execution with the generation of our exception type MyException using throw
        throw new MyException("String can not be empty!");
    }
    return s;
}

Tại sao chúng ta cần một cơ chế ngoại lệ?

Hãy nhìn vào một ví dụ thực tế. Hãy tưởng tượng rằng có một đoạn trên đường cao tốc có cầu khẩn cấp với khả năng chịu tải hạn chế. Nếu một phương tiện có khối lượng vượt quá khả năng chuyên chở của cầu chạy qua cầu, nó có thể bị sập và tình huống đối với người lái xe có thể trở nên, nói một cách nhẹ nhàng, đặc biệt. Để ngăn chặn điều này xảy ra, cơ quan dịch vụ đường bộ đã lắp đặt trước các biển cảnh báo trên đường. Người điều khiển ô tô nhìn vào biển cảnh báo sẽ so sánh trọng lượng của ô tô của mình với trọng lượng cho phép lái xe trên cầu. Nếu vượt quá, anh ta sẽ đi đường vòng. Nhờ hành động của cơ quan dịch vụ đường bộ, trước hết, các tài xế xe tải có cơ hội thay đổi lộ trình trước, thứ hai, họ được cảnh báo về mối nguy hiểm trên tuyến đường chính, và cuối cùng, họ được cảnh báo về việc không thể sử dụng cầu trong những điều kiện nhất định.
Исключения в Java - 2
Khả năng ngăn chặn và giải quyết một ngoại lệ trong chương trình để nó có thể tiếp tục là một trong những lý do sử dụng ngoại lệ trong Java. Cơ chế ngoại lệ cũng cho phép bạn bảo vệ mã bạn viết (giao diện lập trình) khỏi bị người dùng lạm dụng bằng cách xác thực (kiểm tra) dữ liệu đến. Bây giờ chúng ta hãy làm cảnh sát giao thông trong một giây. Đầu tiên, bạn nên biết những nơi mà người lái xe ô tô có thể gặp rắc rối. Thứ hai, bạn cần chuẩn bị và lắp đặt các biển cảnh báo. Cuối cùng, bạn cần cung cấp các tuyến đường vòng phòng trường hợp gặp nguy hiểm trên tuyến đường chính. Trong Java, cơ chế ngoại lệ hoạt động theo cách tương tự. Ở giai đoạn phát triển chương trình, chúng tôi “bảo vệ” các phần mã nguy hiểm khỏi các ngoại lệ bằng cách sử dụng khối try{}, cung cấp các đường dẫn “sao lưu” bằng cách sử dụng khối Catch{} và trong khối cuối cùng{}, chúng tôi viết mã được thực thi trong khối chương trình cho bất kỳ kết quả nào. Trong trường hợp chúng tôi không thể cung cấp “lộ trình khẩn cấp” hoặc cố tình muốn để người dùng lựa chọn, ít nhất chúng tôi phải cảnh báo anh ta về mối nguy hiểm. Tại sao? Hãy tưởng tượng sự phẫn nộ của một người lái xe khi đến một cây cầu khẩn cấp mà không thể lái xe qua mà không gặp phải một biển cảnh báo nào trên đường đi! Trong lập trình, khi viết các lớp và phương thức của mình, chúng tôi không phải lúc nào cũng thấy trước bối cảnh sử dụng của các nhà phát triển khác trong chương trình của họ, vì vậy chúng tôi không thể thấy trước đường dẫn chính xác 100% để giải quyết tình huống ngoại lệ. Đồng thời, cách tốt nhất là cảnh báo người dùng mã của chúng tôi về khả năng xảy ra ngoại lệ. Cơ chế ngoại lệ của Java cho phép chúng ta thực hiện điều này bằng cách sử dụng các lệnh ném—về cơ bản là khai báo hành vi chung của phương thức của chúng ta để ném một ngoại lệ, do đó để người dùng phương thức đó có quyền viết mã để xử lý ngoại lệ trong Java.

Cảnh báo “rắc rối”

Khi bạn không định xử lý một ngoại lệ trong phương thức của mình nhưng muốn cảnh báo người dùng phương thức đó về các tình huống ngoại lệ có thể xảy ra, hãy sử dụng từ khóa ném. Từ khóa này trong chữ ký phương thức có nghĩa là trong một số điều kiện nhất định, phương thức đó có thể đưa ra một ngoại lệ. Cảnh báo này là một phần của giao diện phương thức và cung cấp cho người dùng quyền tùy chỉnh việc triển khai trình xử lý ngoại lệ. Sau khi ném, chúng tôi chỉ ra loại ngoại lệ được ném. Đây thường là hậu duệ của lớp Ngoại lệ Java . Vì Java là ngôn ngữ hướng đối tượng nên tất cả các ngoại lệ trong Java đều là đối tượng.
Исключения в Java - 3

Phân cấp ngoại lệ Java

Khi xảy ra lỗi trong quá trình thực thi chương trình, thời gian chạy JVM sẽ tạo một đối tượng thuộc loại được yêu cầu từ hệ thống phân cấp ngoại lệ Java - tập hợp các ngoại lệ có thể được kế thừa từ một “tổ tiên” chung - lớp Throwable. Các tình huống đặc biệt xảy ra trong một chương trình có thể được chia thành hai nhóm:
  1. Các tình huống không thể khôi phục hoạt động bình thường của chương trình
  2. Có thể phục hồi.
Nhóm đầu tiên bao gồm các tình huống khi xảy ra ngoại lệ được kế thừa từ lớp Lỗi . Đây là những lỗi xảy ra trong quá trình thực thi chương trình do lỗi JVM, tràn bộ nhớ hoặc sự cố hệ thống. Chúng thường chỉ ra những vấn đề nghiêm trọng không thể khắc phục bằng phần mềm. Loại ngoại lệ này trong Java được phân loại là không được kiểm tra ở giai đoạn biên dịch. Nhóm này cũng bao gồm RuntimeException - các ngoại lệ, phần kế thừa của lớp Exception , do JVM tạo ra trong quá trình thực thi chương trình. Chúng thường được gây ra bởi lỗi lập trình. Những ngoại lệ này cũng không được đánh dấu tại thời điểm biên dịch nên việc viết mã để xử lý chúng là không cần thiết. Nhóm thứ hai bao gồm các tình huống đặc biệt được dự đoán trước ở giai đoạn viết chương trình và phải viết mã xử lý. Những trường hợp ngoại lệ như vậy được kiểm tra. Phần lớn công việc của nhà phát triển Java khi xử lý các ngoại lệ là xử lý các tình huống như vậy.

Tạo một ngoại lệ

Trong quá trình thực thi chương trình, một ngoại lệ được JVM đưa ra hoặc sử dụng câu lệnh ném theo cách thủ công . Điều này tạo ra một đối tượng ngoại lệ trong bộ nhớ và làm gián đoạn việc thực thi mã chương trình chính trong khi trình xử lý ngoại lệ JVM cố gắng tìm cách xử lý ngoại lệ đó.

Xử lý ngoại lệ

Việc tạo các khối mã mà chúng tôi cung cấp khả năng xử lý ngoại lệ trong Java được thực hiện trong chương trình bằng cách sử dụng các cấu trúc try{}catch, try{}catch{}cuối cùng, thử{}cuối cùng{}.
Исключения в Java - 4
Khi một ngoại lệ được đưa ra trong khối thử, trình xử lý ngoại lệ sẽ được tìm kiếm trong khối bắt sau. Nếu phần bắt có chứa một trình xử lý cho loại ngoại lệ này, thì quyền điều khiển sẽ chuyển đến nó. Nếu không, JVM sẽ tìm kiếm một trình xử lý cho loại ngoại lệ đó trong chuỗi lệnh gọi phương thức cho đến khi tìm thấy một lệnh bắt phù hợp. Sau khi khối bắt được thực thi, điều khiển được chuyển đến khối cuối cùng tùy chọn . Nếu không tìm thấy khối bắt phù hợp, JVM sẽ dừng thực thi chương trình và hiển thị một chồng lệnh gọi phương thức - dấu vết ngăn xếp , trước đó đã thực thi mã khối cuối cùng, nếu có. Ví dụ xử lý ngoại lệ:
public class Print {

     void print(String s) {
        if (s == null) {
            throw new NullPointerException("Exception: s is null!");
        }
        System.out.println("Inside method print: " + s);
    }

    public static void main(String[] args) {
        Print print = new Print();
        List list= Arrays.asList("first step", null, "second step");

        for (String s:list) {
            try {
                print.print(s);
            }
            catch (NullPointerException e) {
                System.out.println(e.getMessage());
                System.out.println("Exception was processed. Program continues");
            }
            finally {
                System.out.println("Inside bloсk finally");
            }
            System.out.println("Go program....");
            System.out.println("-----------------");
        }

    }
    }
Kết quả của phương pháp chính :
Inside method print: first step
Inside bloсk finally
Go program....
-----------------
Exception: s is null!
Exception was processed. Program continues
Inside bloсk finally
Go program....
-----------------
Inside method print: second step
Inside bloсk finally
Go program....
-----------------
Khối này finallythường được sử dụng để đóng các luồng được mở trong khối thử hoặc để giải phóng tài nguyên. Tuy nhiên, khi viết một chương trình, không phải lúc nào cũng có thể theo dõi được việc đóng tất cả các tài nguyên. Để làm cho cuộc sống của chúng ta dễ dàng hơn, các nhà phát triển Java đã cung cấp cho chúng ta một cấu trúc try-with-resourcestự động đóng các tài nguyên được mở trong khối thử. Ví dụ đầu tiên của chúng ta có thể được viết lại như thế này try-with-resources:
public String input() throws MyException {
    String s = null;
    try(BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))){
        s = reader.readLine();
   } catch (IOException e) {
       System.out.println(e.getMessage());
   }
    if (s.equals("")){
        throw new MyException ("String can not be empty!");
    }
    return s;
}
Nhờ khả năng của Java, bắt đầu từ phiên bản 7, chúng ta cũng có thể kết hợp việc bắt các loại ngoại lệ khác nhau trong một khối duy nhất, làm cho mã trở nên nhỏ gọn và dễ đọc hơn. Ví dụ:
public String input() {
    String s = null;
    try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) {
        s = reader.readLine();
        if (s.equals("")) {
            throw new MyException("String can not be empty!");
        }
    } catch (IOException | MyException e) {
        System.out.println(e.getMessage());
    }
    return s;
}

Kết quả

Việc sử dụng các ngoại lệ trong Java cho phép chúng ta tăng khả năng chịu lỗi của chương trình thông qua việc sử dụng các đường dẫn “dự phòng”, tách logic của mã chính khỏi mã xử lý ngoại lệ thông qua việc sử dụng các khối bắt và cũng cho chúng ta cơ hội ủy quyền xử lý ngoại lệ cho người dùng mã của chúng tôi bằng cách sử dụng lệnh ném.
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION