Tại sao “ném Ngoại lệ” lại cần thiết khi gọi một hàm?


97
class throwseg1
{
    void show() throws Exception
    {
        throw new Exception("my.own.Exception");
    }

    void show2() throws Exception  // Why throws is necessary here ?
    {
        show();
    }

    void show3() throws Exception  // Why throws is necessary here ?
    {
        show2();
    }

    public static void main(String s[]) throws Exception  // Why throws is necessary here ?
    {
        throwseg1 o1 = new throwseg1();
        o1.show3();
    }
}

Tại sao các báo cáo trình biên dịch rằng phương pháp show2(), show3()main()

ngoại lệ không được báo cáo Ngoại lệ phải được bắt hoặc khai báo để ném

khi tôi xóa throws Exceptionkhỏi các phương pháp này?


2
@PaulTomblin main chắc chắn có thể được khai báo để ném Exception. Nếu đúng như vậy, JVM sẽ ngừng hoạt động. Điều này gần như bỏ qua nó vì trình biên dịch sẽ cho phép.
Taymon

Khi phương thức được gọi ( Methdod1 ) ném Exception, chúng ta phải xác định phương thức gọi ( Method2 ) với throws Exception; nếu chúng tôi không đưa ra ngoại lệ đó trong phương thức gọi. Mục đích của việc này là cung cấp thông tin cho phương thức gọi ( Method3 ) của Method2 mà một Ngoại lệ có thể bị Method2 ném ra và bạn nên xử lý nó ở đây, nếu không nó có thể làm gián đoạn chương trình của bạn.
Rito

Tương tự, nếu Method3 không xử lý ngoại lệ trong phần thân của nó thì nó phải xác định throws Exceptiontrong định nghĩa phương thức của nó để đưa ra phương thức gọi của nó. mở rộng của comment trước
Rito

Câu trả lời:


144

Trong Java, như bạn có thể biết, các ngoại lệ có thể được phân loại thành hai: Một là cần throwsmệnh đề hoặc phải được xử lý nếu bạn không chỉ định một và một ngoại lệ khác thì không. Bây giờ, hãy xem hình sau:

nhập mô tả hình ảnh ở đây

Trong Java, bạn có thể ném bất kỳ thứ gì mở rộng Throwablelớp. Tuy nhiên, bạn không cần phải chỉ định một throwsmệnh đề cho tất cả các lớp. Cụ thể, các lớp là một Errorhoặc RuntimeExceptionhoặc bất kỳ lớp nào trong số hai lớp này. Trong trường hợp của bạn Exceptionkhông phải là một lớp con của Errorhoặc RuntimeException. Vì vậy, nó là một ngoại lệ đã được kiểm tra và phải được chỉ định trong throwsmệnh đề, nếu bạn không xử lý ngoại lệ cụ thể đó. Đó là lý do tại sao bạn cần throwsđiều khoản.


Từ Hướng dẫn Java :

Một ngoại lệ là một sự kiện, xảy ra trong quá trình thực thi một chương trình, làm gián đoạn luồng hướng dẫn bình thường của chương trình.

Bây giờ, như bạn biết, các trường hợp ngoại lệ được phân loại thành hai: được chọn và không được chọn. Tại sao lại phân loại?

Ngoại lệ được kiểm tra: Chúng được sử dụng để đại diện cho các vấn đề có thể được khôi phục trong quá trình thực hiện chương trình. Chúng thường không phải là lỗi của lập trình viên. Ví dụ: không thể đọc được tệp do người dùng chỉ định hoặc không có kết nối mạng, v.v. Trong tất cả các trường hợp này, chương trình của chúng tôi không cần phải thoát, thay vào đó, chương trình có thể thực hiện các hành động như cảnh báo người dùng hoặc chuyển sang trạng thái dự phòng cơ chế (như hoạt động ngoại tuyến khi mạng không khả dụng), v.v.

Các ngoại lệ không được kiểm tra: Chúng một lần nữa có thể được chia thành hai: Lỗi và Ngoại lệ thời gian chạy . Một lý do để chúng không được kiểm tra là chúng có số lượng rất nhiều và việc yêu cầu xử lý tất cả chúng sẽ làm chương trình của chúng ta lộn xộn và giảm độ rõ ràng của nó. Lý do khác là:

  • Ngoại lệ thời gian chạy: Chúng thường xảy ra do lỗi của lập trình viên. Ví dụ, nếu một phép ArithmeticExceptionchia cho số 0 xảy ra hoặc ArrayIndexOutOfBoundsExceptionxảy ra, đó là do chúng ta không đủ cẩn thận trong việc viết mã của mình. Chúng thường xảy ra do một số lỗi trong logic chương trình của chúng tôi. Vì vậy, chúng phải được xóa trước khi chương trình của chúng tôi đi vào chế độ sản xuất. Chúng không được kiểm tra theo nghĩa là chương trình của chúng tôi phải bị lỗi khi nó xảy ra, để các lập trình viên của chúng tôi có thể giải quyết nó tại thời điểm phát triển và tự kiểm tra.

  • Lỗi: Lỗi là những tình huống mà chương trình thường không thể khôi phục. Ví dụ, nếu một StackOverflowErrorxảy ra, chương trình của chúng tôi không thể làm gì nhiều, chẳng hạn như tăng kích thước của ngăn xếp gọi hàm của chương trình. Hoặc nếu OutOfMemoryErrorxảy ra, chúng tôi không thể làm gì nhiều để tăng dung lượng RAM có sẵn cho chương trình của mình. Trong những trường hợp như vậy, tốt hơn là thoát khỏi chương trình. Đó là lý do tại sao chúng không được kiểm soát.

Thông tin chi tiết xem:


những gì tôi nhận được từ câu trả lời của bạn là lớp Lỗi và lớp phụ và lớp RuntimeException cũng như các lớp con của nó, chúng nằm trong ngoại lệ không được kiểm tra (như System.out.println (5/0); không cần phải ném vì nó là một ngoại trừ thời gian chạy nhưng chúng ta vẫn có thể áp dụng cố gắng nắm bắt) và lớp ngoại lệ được kiểm tra vì vậy chúng tôi cần phải khai báo ném điều khoản trong đó phương pháp và mọi phương pháp mà các cuộc gọi nó
nr5

Một câu hỏi nữa: nếu các ngoại lệ được phân loại thành không kiểm tra và kiểm tra, đặc biệt là các ngoại lệ không kiểm tra (lỗi thời gian chạy) để tránh nhiều lỗi hơn trong thời gian biên dịch?
nr5

@Jomoos - Nói rằng mã bên trong một phương thức ném IOException. Sau đó, có thể đặt "ném Ngoại lệ" vào khai báo của phương thức không?
MasterJoe

Oh. Bây giờ tôi hiểu rồi. có một ngoại lệ đối với các quy tắc của cấu trúc phân cấp Ngoại lệ. Làm cho. Hoàn hảo. Giác quan. Cảm ơn Java.
JJS

25

Java yêu cầu bạn xử lý hoặc khai báo tất cả các ngoại lệ. Nếu bạn không xử lý Ngoại lệ bằng khối try / catch thì nó phải được khai báo trong chữ ký của phương thức.

Ví dụ:

class throwseg1 {
    void show() throws Exception {
        throw new Exception();
    }
}

Nên viết là:

class throwseg1 {
    void show() {
        try {
            throw new Exception();
        } catch(Exception e) {
            // code to handle the exception
        }
    }
}

Bằng cách này, bạn có thể loại bỏ khai báo "ném ngoại lệ" trong khai báo phương thức.


7
Đó là tất cả các ngoại lệ không phải là lớp con của RuntimeException.
yshavit

nếu có bất kỳ lớp nào khác như Exception được kiểm tra không?
nr5,

1
Ý anh là gì? Vì tất cả các đối tượng ngoại lệ đều có "Ngoại lệ" làm lớp cơ sở của chúng, nếu bạn bắt một đối tượng "Ngoại lệ" (như trong ví dụ của tôi), nó sẽ bắt bất kỳ ngoại lệ nào được ném ra. Để cụ thể hơn (vì các ngoại lệ khác nhau có thể sẽ yêu cầu các cách xử lý mọi thứ khác nhau), bạn nên có nhiều khối bắt.
jebar 8

nếu tôi muốn nói rằng các ngoại lệ đã kiểm tra cần được xử lý @ thời gian biên dịch và bị bắt trong thời gian chạy. Tôi nói đúng chứ? nếu có thì cụm từ tương tự cho ngoại lệ Bỏ chọn sẽ là?
nr5, 21-07-12

@ jebar8 - bạn đang nhầm lẫn Java với .NET - trong Java, các tệp có thể ném phải kế thừa Throwable(kế thừa Exceptioncũng hoạt động, vì nó mở rộng Throwable, nhưng không bắt buộc).
BrainSlugs83

4

Exceptionlà một lớp ngoại lệ đã được kiểm tra. Do đó, bất kỳ mã nào gọi một phương thức khai báo rằng nó throws Exceptionphải xử lý hoặc khai báo nó.


Mọi phương thức trong chuỗi đều được khai báo để ném Exception, bao gồm cả main. Vậy vấn đề là ở đâu?
Paul Tomblin

@PaulTomblin tôi đang hỏi rằng tại sao cần phải viết ngoại lệ ném trong các hàm gọi, gọi một hàm ném ngoại lệ
nr5

Được rồi, tôi không hiểu tại sao bạn lại hỏi về lỗi trình biên dịch mà bạn thực sự không nhận được từ mã bạn đã đăng. Đó là một cách hỏi kỳ quặc.
Paul Tomblin

4

Các throws Exceptiontuyên bố là một cách tự động theo dõi các phương pháp mà có thể ném một ngoại lệ vì lý do dự đoán nhưng không thể tránh khỏi. Khai báo thường cụ thể về loại hoặc các loại ngoại lệ có thể được đưa ra chẳng hạn như throws IOExceptionhoặc throws IOException, MyException.

Tất cả chúng ta đều có hoặc cuối cùng sẽ viết mã dừng đột ngột và báo cáo một ngoại lệ do điều gì đó chúng ta không lường trước được trước khi chạy chương trình, chẳng hạn như chia cho 0 hoặc lập chỉ mục ngoài giới hạn. Vì các lỗi không được mong đợi bởi phương pháp, chúng không thể được "bắt" và xử lý bằng mệnh đề try catch. Bất kỳ người dùng không nghi ngờ nào của phương pháp cũng sẽ không biết về khả năng này và chương trình của họ cũng sẽ dừng lại.

Khi lập trình viên biết một số loại lỗi nhất định có thể xảy ra nhưng muốn xử lý các ngoại lệ này bên ngoài phương thức, phương thức có thể "ném" một hoặc nhiều loại ngoại lệ vào phương thức gọi thay vì xử lý chúng. Nếu người lập trình không khai báo rằng phương thức (có thể) ném một ngoại lệ (hoặc nếu Java không có khả năng khai báo nó), thì trình biên dịch sẽ không thể biết được và người dùng phương thức này sẽ phải biết về điều đó, bắt và xử lý bất kỳ ngoại lệ nào mà phương thức có thể ném ra. Vì các chương trình có thể có nhiều lớp phương thức được viết bởi nhiều chương trình khác nhau, nên rất khó (không thể) để theo dõi các phương thức nào có thể tạo ra ngoại lệ.

Mặc dù Java có khả năng khai báo các ngoại lệ, bạn vẫn có thể viết một phương thức mới với các ngoại lệ chưa được khai báo và chưa được khai báo, và Java sẽ biên dịch nó và bạn có thể chạy nó và hy vọng điều tốt nhất. Những gì Java sẽ không cho phép bạn làm là biên dịch phương thức mới của bạn nếu nó sử dụng một phương thức đã được khai báo là ném (các) ngoại lệ, trừ khi bạn xử lý (các) ngoại lệ đã khai báo trong phương thức của mình hoặc khai báo phương thức của bạn là ném cùng một (các) ngoại lệ hoặc nếu có nhiều ngoại lệ, bạn có thể xử lý một số và ném phần còn lại.

Khi một lập trình viên tuyên bố rằng phương thức ném ra một loại ngoại lệ cụ thể, nó chỉ là một cách tự động để cảnh báo những lập trình viên khác sử dụng phương thức rằng một ngoại lệ có thể xảy ra. Sau đó, lập trình viên có thể quyết định xử lý ngoại lệ hoặc chuyển cảnh báo bằng cách khai báo phương thức gọi cũng như ném ngoại lệ tương tự. Vì trình biên dịch đã được cảnh báo rằng có thể có ngoại lệ trong phương thức mới này, nên nó có thể tự động kiểm tra xem những người gọi phương thức mới trong tương lai có xử lý ngoại lệ hay không hoặc khai báo nó và thực thi điều này hay điều khác xảy ra.

Điều thú vị về loại giải pháp này là khi trình biên dịch báo cáo, Error: Unhandled exception type java.io.IOExceptionnó sẽ cung cấp tệp và số dòng của phương thức được khai báo để ném ngoại lệ. Sau đó, bạn có thể chọn chỉ cần vượt qua buck và khai báo phương thức của bạn cũng "ném IOException". Điều này có thể được thực hiện theo cách cho đến phương thức chính mà sau đó nó sẽ khiến chương trình dừng lại và báo cáo ngoại lệ cho người dùng. Tuy nhiên, tốt hơn là bạn nên nắm bắt ngoại lệ và giải quyết nó theo cách tốt đẹp như giải thích cho người dùng những gì đã xảy ra và cách khắc phục nó. Khi một phương thức bắt và xử lý ngoại lệ, nó không còn phải khai báo ngoại lệ nữa. Buck dừng lại ở đó để nói.


0
package javaexception;


public class JavaException {
   void show() throws Exception
    {
        throw new Exception("my.own.Exception");
    }

void show2() throws Exception  // Why throws is necessary here ?
{
    show();
}

void show3() throws Exception  // Why throws is necessary here ?
{
    show2();
}
public static void main(String[] args) {

   JavaException a = new JavaException();

   try{
   a.show3();
   }catch(Exception e){
       System.out.println(e.getMessage());
   }
}

Chỉ những thay đổi nhỏ trong chương trình của bạn. Điều Có vẻ như bị nhiều người hiểu lầm về vấn đề chính, là bất cứ khi nào bạn ném ngoại lệ, bạn cần xử lý nó, không cần thiết ở cùng một nơi (ví dụ: phương thức show1,2,3 trong chương trình của bạn) nhưng trước tiên bạn phải gọi phương thức bên trong 'chính'. trong một từ, có 'ném', phải có 'bắt / thử', ngay cả khi không cùng một phương thức mà ngoại lệ xảy ra.


0
void show() throws Exception
{
    throw new Exception("my.own.Exception");
}

Vì có một ngoại lệ được kiểm tra trong phương thức show (), phương thức này không được xử lý trong phương thức đó, vì vậy chúng tôi sử dụng từ khóa throws để truyền ngoại lệ.

void show2() throws Exception //Why throws is necessary here ?
{
show();
}

Vì bạn đang sử dụng phương thức show () trong phương thức show2 () và bạn đã phổ biến ngoại lệ ít nhất mà bạn nên xử lý ở đây. Nếu bạn không xử lý Exception ở đây, thì bạn đang sử dụng từ khóa throws. Vì vậy, đó là lý do sử dụng từ khóa throws ở chữ ký phương thức.


0

Nếu bạn tuyên truyền ngoại lệ bằng cách khai báo chỉ thị ném trong chữ ký của phương thức hiện tại, thì ở đâu đó trên dòng hoặc gọi ngăn xếp một cấu trúc try / catch phải được sử dụng để xử lý ngoại lệ.


Nhận xét này nên được thêm vào phần nhận xét vì nó không cung cấp câu trả lời có thể xác minh hoặc ví dụ về một. - stackoverflow.com/help/how-to-answer
Paul Dawson

-1

Về cơ bản, nếu bạn không xử lý ngoại lệ ở cùng một nơi mà bạn đang ném nó, thì bạn có thể sử dụng "ném ngoại lệ" ở định nghĩa của hàm.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.