CodeGym /Các khóa học /JAVA 25 SELF /Chuyển tiếp ngoại lệ (throws)

Chuyển tiếp ngoại lệ (throws)

JAVA 25 SELF
Mức độ , Bài học
Có sẵn

1. Giới thiệu

Trong lập trình thường có những tình huống khi một phương thức gặp lỗi nhưng không biết cách xử lý cho đúng. Ví dụ, phương thức đọc một tệp nhưng không biết phải làm gì nếu tệp không tồn tại: hỏi người dùng? Kết thúc chương trình? Thử một tệp khác? Trong những trường hợp như vậy, phương thức có thể “chuyển trách nhiệm” cho bên gọi — tức là “chuyển tiếp” ngoại lệ tiếp tục theo chuỗi lời gọi.

Chuyển tiếp ngoại lệ là cơ chế cho phép một phương thức không tự xử lý lỗi, mà thông báo cho mã gọi: “Tôi có vấn đề ở đây, hãy tự xử lý!”

Tương tự: Hãy tưởng tượng bạn là nhân viên tổng đài. Khách gọi đến với một câu hỏi mà bạn không biết câu trả lời. Thay vì đoán mò, bạn nói: “Xin chờ một chút, tôi sẽ nối máy với chuyên gia.” Bạn “chuyển tiếp” câu hỏi đi tiếp.

Từ khóa throws: hoạt động như thế nào

Trong Java, để chuyển tiếp ngoại lệ sử dụng từ khóa throws trong khai báo phương thức.

Cú pháp:

tip_vozvrashchaemogo_znacheniya imyaMetoda(...) throws ExceptionType 
{
    // mã của phương thức
}

Sau throws là kiểu ngoại lệ có thể phát sinh trong phương thức này. Đây giống như lời cảnh báo cho các lập trình viên khác: “Chú ý! Phương thức này có thể ném ngoại lệ kiểu này. Hãy sẵn sàng!”

Ví dụ:

public void readFile(String filename) throws FileNotFoundException 
{
    FileReader reader = new FileReader(filename); // có thể ném FileNotFoundException
    // ...
}

Ở đây phương thức readFile không tự xử lý lỗi, mà thông báo: “Tôi có thể ném FileNotFoundException — hãy để người gọi tôi quyết định phải làm gì”.

2. Phương thức gọi nên phản ứng thế nào?

Nếu bạn gọi một phương thức được khai báo với throws, bạn có hai lựa chọn:

  • Xử lý ngoại lệ bằng try-catch
  • Cũng chuyển tiếp ngoại lệ đi tiếp (thêm throws vào phương thức của bạn)

Lựa chọn 1: xử lý qua try-catch

public static void main(String[] args) 
{
    try 
    {
        readFile("data.txt");
    } 
    catch (FileNotFoundException e) 
    {
        System.out.println("Không tìm thấy tệp: " + e.getMessage());
    }
}

Ở đây chúng ta bắt ngoại lệ và tự quyết định phải làm gì (ví dụ, hiển thị thông báo cho người dùng).

Lựa chọn 2: chuyển tiếp lên trên

public static void main(String[] args) throws FileNotFoundException 
{
    readFile("data.txt");
}

Bây giờ trách nhiệm xử lý lỗi thuộc về bên gọi main (thông thường là chính JVM — nếu lỗi không được xử lý, chương trình sẽ kết thúc với thông báo lỗi).

3. Ví dụ: đọc tệp với chuyển tiếp ngoại lệ

Ví dụ đầy đủ với IOException và xử lý ở cấp độ main:

import java.io.*;

public class FileDemo 
{
    // Phương thức khai báo rằng có thể ném ra IOException
    public static void printFirstLine(String filename) throws IOException 
    {
        BufferedReader reader = new BufferedReader(new FileReader(filename));
        String line = reader.readLine();
        System.out.println("Dòng đầu tiên: " + line);
        reader.close();
    }

    public static void main(String[] args) 
    {
        try 
        {
            printFirstLine("nofile.txt");
        } 
        catch (IOException e) 
        {
            System.out.println("Lỗi khi đọc tệp: " + e.getMessage());
        }
    }
}

Phương thức printFirstLine không biết phải làm gì nếu tệp không tồn tại — nó chỉ chuyển tiếp ngoại lệ. Trong main chúng ta bắt lỗi và in ra thông báo.

4. Những điểm hữu ích

Khi nào và tại sao nên dùng chuyển tiếp ngoại lệ?

  • Khi phương thức không thể hoặc không nên quyết định cách xử lý lỗi (ví dụ, mã thư viện).
  • Khi việc xử lý lỗi phụ thuộc vào ngữ cảnh (trường hợp này kết thúc chương trình, trường hợp khác — thử tệp khác).
  • Để không làm rối mã với các khối try-catch không cần thiết.

Best practice: Hãy chuyển tiếp ngoại lệ nếu bạn không thể xử lý chúng một cách có ý nghĩa. Đừng bắt ngoại lệ chỉ để cho có!

Có thể chuyển tiếp nhiều ngoại lệ

public void process() throws IOException, SQLException 
{
    // ...
}

Ngoại lệ checked và unchecked: nhắc lại

Checked exceptions (ví dụ, IOException, SQLException) — trình biên dịch yêu cầu phải xử lý hoặc chuyển tiếp chúng.

Unchecked exceptions (ví dụ, NullPointerException, IllegalArgumentException) — trình biên dịch không yêu cầu xử lý, bạn có thể không nêu trong throws.

5. Những lỗi thường gặp khi chuyển tiếp ngoại lệ

Lỗi số 1: quên khai báo throws cho ngoại lệ checked.
Nếu một phương thức có thể ném ngoại lệ checked, nhưng bạn không khai báo nó trong throws và cũng không xử lý qua try-catch — trình biên dịch sẽ báo lỗi.

Lỗi số 2: bắt ngoại lệ nhưng không xử lý nó.
Viết catch (Exception e) {} — là thực hành tệ! Tốt hơn hãy chuyển tiếp ngoại lệ nếu bạn không biết phải làm gì với nó.

Lỗi số 3: chuyển tiếp kiểu quá tổng quát.
Nếu phương thức chỉ có thể ném FileNotFoundException, đừng viết throws Exception — điều đó làm khó việc hiểu mã.

Lỗi số 4: đưa các ngoại lệ unchecked vào throws.
Không có ý nghĩa gì khi viết throws NullPointerException — trình biên dịch không yêu cầu điều đó và nó cũng không giúp ích cho việc xử lý lỗi.

1
Nhiệm vụ
JAVA 25 SELF, mức độ, bài học
Đã khóa
Mô-đun truy cập tài liệu bí mật 📁
Mô-đun truy cập tài liệu bí mật 📁
1
Nhiệm vụ
JAVA 25 SELF, mức độ, bài học
Đã khóa
Công cụ phân tích log: xử lý lỗi đọc 📊
Công cụ phân tích log: xử lý lỗi đọc 📊
1
Nhiệm vụ
JAVA 25 SELF, mức độ, bài học
Đã khóa
Pipeline xử lý dữ liệu: các vấn đề có thể gặp với tệp ⚙️
Pipeline xử lý dữ liệu: các vấn đề có thể gặp với tệp ⚙️
1
Nhiệm vụ
JAVA 25 SELF, mức độ, bài học
Đã khóa
Cơn sốt vàng: chuyển đổi đầu vào của người chơi 💰
Cơn sốt vàng: chuyển đổi đầu vào của người chơi 💰
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION