Checked và Unchecked Exception trong Java

Bài viết được sự cho phép của tác giả Edward Thiên Hoàng

CHECKED VÀ UNCHECKED EXCEPTION TRONG JAVA

CƠ BẢN

Trong Java có 2 loại exception: checked và unchecked. Tất cả các checked exception được kế thừa từ lớp Exception ngoại trừ lớp RuntimeException. RuntimeException là lớp cơ sở của tất cả các lớp unchecked exception. Đó cũng là dấu hiệu để nhận biết đâu là checked exception và đâu là unchecked exception. Cùng xem qua hierarchy của tất cả các lớp exception:

KHÁC NHAU GIỮA CHECKED VÀ UNCHECKED EXCEPTION

Điểm khác biệt giữa các lớp checked và unchecked expcetion chính là thời điểm xác định được expcetion có thể xảy ra. Đối với checked exception, việc kiểm tra được thực hiện ngay thời điểm compile time, một số IDE sẽ giúp chúng ta bằng cách hiển thị lỗi cú pháp nếu ta gọi một method throw ra bất kỳ checked exception nào mà không được catch. Một số checked exception tiêu biểu như: IOException, InterruptedException, XMLParseException.. Còn đối với unchecked exception, việc xác định có exception xảy ra hay không chỉ có thể thực hiện ở thời điểm runtime, và các IDE sẽ không giúp chúng ta xác định được chuyện đó. Một số unchecked exception tiêu biểu là: NullPointerException, IndexOutOfBoundsException, ClassCastException… Hãy xem các ví dụ để hiểu rõ hơn.

  10 Java Web Framework tốt nhất
  10 lý do cho thấy tại sao bạn nên theo học ngôn ngữ lập trình Java

CHECKED EXCEPTION

Hãy xét qua ví dụ với IOException:

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class MainCheckedAndUncheckedException {

    public static void main(String[] args) {

        BufferedReader br = null;

        try {

            String sCurrentLine;

            br = new BufferedReader(new FileReader("C:\\testing.txt"));

            while ((sCurrentLine = br.readLine()) != null) {
                System.out.println(sCurrentLine);
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (br != null)
                    br.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }

    }
}

Ở đoạn trên, nếu ta remove phần try-catch thì IDE sẽ báo lỗi:

Unhandled exception type FileNotFoundException đối với method: FileReader(…)
Unhandled exception type IOException đối với method: readLine()

Bây giờ hãy viết riêng một method để test

public class MainCheckedAndUncheckedException {

    public static void main(String[] args) {
        try {
            doParseXML();
        } catch (XMLParseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void doParseXML() throws XMLParseException, IOException {
        doOpenXML();
        // Do parse XML. This method may be thrown a checked exception
    }

    private static void doOpenXML() throws IOException {
        // Do open XML. This method may be thrown a checked exception
    }
}

Method doOpenXML được dánh dấu là sẽ throw ra IOException, do vậy, bất cứ method nào gọi doOpenXML đều phải catch nó hoặc đánh dấu là sẽ throw ra exception của method nó gọi. Trong trường hợp này doParseXML gọi doOpenXML và quyết định throw ra IOException của doOpenXML. Đồng thời nó cũng throw thêm 1 exception là XMLParseException. Và method main gọi doParseXML chọn cách catch các exception của doParseXML có thể throw.

Ứng tuyển các vị trí việc làm Java lương cao trên TopDev

UNCHECKED EXCEPTION:

public class MainCheckedAndUncheckedException {

    public static void main(String[] args) {
        printArray();
    }

    private static void printArray() {
        int[] array = new int[1];
        System.out.println(array[1]);
    }
}

Với đoạn code trên sẽ có 1 exception được throw ra mà không hề báo trước:

Exception in thread “main” java.lang.ArrayIndexOutOfBoundsException: 1
at com.edward.tutorial.corejava.exception.MainCheckedAndUncheckedException.printArray(MainCheckedAndUncheckedException.java:12)
at com.edward.tutorial.corejava.exception.MainCheckedAndUncheckedException.main(MainCheckedAndUncheckedException.java:7)

Dù cho ta có đánh dấu method printArray sẽ throw ra ArrayIndexOutOfBoundsException thì IDE vẫn không báo lỗi khi hàm main gọi đến hàm printArray bởi vì ArrayIndexOutOfBoundsException là 1 unchecked exception

public class MainCheckedAndUncheckedException {

    public static void main(String[] args) {
        printArray();
    }

    private static void printArray() throws ArrayIndexOutOfBoundsException {
        int[] array = new int[1];
        System.out.println(array[1]);
    }
}

CHECKED VÀ UNCHECKED EXCEPTION USE CASES

Vậy một câu hỏi đặt ra khi design API là khi nào một method sẽ throw checked exception, và khi nào sẽ throw unchecked exception.

Throw unchecked exception trong trường hợp chương trình bị sai về logic, không thể làm gì tiếp theo nếu gặp những lỗi đó, ví dụ như có 1 biến null hoặc không hợp lệ khiến toàn bộ đoạn chương trình phía sau không thể làm tiếp, ta sẽ throw NullPointerException hoặc IllegalArgumentException. Còn trong trường hợp những lỗi vẫn còn có thể handle được thì throw checked exception. Ví dụ như method open file có thể throw FileNotFoundException nhằm mục đích cảnh báo khi client gọi đến method này, cần phải handle trường hợp không tìm thấy file lúc đọc file. Đó không phải là lỗi logic chương trình mà là 1 ngoại lệ khác với kết quả mong muốn từ việc đọc file.

Bài viết gốc được đăng tải tại edwardthienhoang.wordpress.com

Có thể bạn quan tâm:

Xem thêm Tuyển dụng Java hấp dẫn trên TopDev