thử / bắt so với ném Ngoại lệ


117

Các câu lệnh này có tương đương nhau không? Có sự khác biệt nào giữa chúng không?

private void calculateArea() throws Exception {
    ....do something
}

private void calculateArea() {
    try {
        ....do something
    } catch (Exception e) {
        showException(e);
    }
}

3
Không hẳn là một câu trả lời, nhưng bạn có thể quan tâm đến bài viết Ngoại lệ trong Rừng nhiệt đới của Ned Batchelder , giúp giải thích các trường hợp chung mà phong cách này hay phong cách khác được ưa thích hơn.
Daniel Pryden

1
thay vì có "showException (e)" trong phần bắt, bạn đã hỏi liệu bạn có "ném e" trong phần bắt hay không (hoặc không có thử / bắt gì cả)?
MacGyver

Câu trả lời:


146

Vâng, có một sự khác biệt rất lớn - cái thứ hai nuốt chửng ngoại lệ (thừa nhận là hiển thị nó), trong khi cái đầu tiên sẽ để nó lan truyền. (Tôi cho rằng điều đó showExceptionkhông làm nó mọc lại.)

Vì vậy, nếu bạn gọi phương thức đầu tiên và "làm gì đó" không thành công, thì người gọi sẽ phải xử lý ngoại lệ. Nếu bạn gọi phương thức thứ hai và "làm gì đó" không thành công, thì người gọi sẽ không thấy ngoại lệ nào cả ... điều này nói chung là một điều tồi tệ, trừ khi showExceptionđã thực sự xử lý ngoại lệ, sửa bất cứ điều gì sai và nói chung là đảm bảo điều đó calculateAreađã đạt được mục đích của nó.

Bạn sẽ có thể nói điều này, bởi vì bạn không thể gọi phương pháp đầu tiên mà không cần một trong hai bắt Exceptionmình hoặc tuyên bố rằng phương pháp của bạn có thể ném nó quá.


12
Khi bạn đề cập rằng "Trừ khi nó thực sự xử lý ngoại lệ", đó là một điểm tuyệt vời. Tôi chỉ nghĩ rằng tôi muốn thêm rằng bản thân việc bắt "Exception" hiếm khi dẫn đến "xử lý" thông minh đối với ngoại lệ thực tế, đó là lý do mọi người khuyên bạn nên bắt ngoại lệ cụ thể nhất có thể.
Bill K

17
+1. Vì Jon Skeet cần thêm danh tiếng. Ồ, và câu trả lời cũng rất hay.
Jonathan Spiller

20

Đầu tiên throws Exception, người gọi cần phải xử lý Exception. ExceptionCái thứ hai bắt và xử lý nội bộ, vì vậy người gọi không phải thực hiện bất kỳ xử lý ngoại lệ nào.


Vì vậy, tóm lại, tôi luôn nên sử dụng cái thứ hai. Tôi nói đúng chứ? Phương thức đầu tiên thực sự là một phương thức được sử dụng ở các điểm khác nhau của chương trình. Đó là lý do tại sao tôi quyết định đọc lại các hướng dẫn để sử dụng thêm nhưng sau khi làm xong, tôi nhận ra rằng T đã mắc một sai lầm lớn ..
carlos

9
Không, cả hai mẫu đều cần thiết. Nếu phương thức của bạn có thể xử lý ngoại lệ, hãy sử dụng mẫu thứ hai, nếu không, hãy sử dụng mẫu đầu tiên để thông báo cho người gọi.
Andreas Dolk,

Bạn sử dụng phiên bản nào tùy thuộc vào yêu cầu của bạn - về cơ bản bạn cần ở cấp độ nào để xử lý ngoại lệ đó. Người gọi cần được mã hóa tương ứng. Nếu người gọi đang gọi phiên bản đầu tiên và bạn thay thế định nghĩa phương thức bằng phiên bản thứ hai, mã người gọi của bạn sẽ bị buộc xử lý ngoại lệ vì đây là ngoại lệ đã được kiểm tra.
samitgaur

16

Đúng. Phiên bản khai báo throws Exceptionsẽ yêu cầu mã gọi để xử lý ngoại lệ, trong khi phiên bản xử lý rõ ràng nó sẽ không.

tức là, đơn giản là:

performCalculation();

so với chuyển gánh nặng xử lý ngoại lệ cho người gọi:

try {
    performCalculation();
catch (Exception e) {
    // handle exception
}

6

Vâng, có rất nhiều sự khác biệt giữa chúng. Trong khối mã đầu tiên, bạn chuyển ngoại lệ cho mã gọi. Trong khối mã thứ hai bạn tự xử lý. Phương pháp nào là đúng hoàn toàn phụ thuộc vào những gì bạn đang làm. Trong một số trường hợp, bạn muốn mã của mình xử lý ngoại lệ (ví dụ: nếu không tìm thấy tệp và bạn muốn tạo nó) nhưng trong những trường hợp khác, bạn muốn mã gọi xử lý ngoại lệ (không tìm thấy tệp và họ cần chỉ định một cái mới hoặc tạo nó).

Nói chung, bạn không muốn mắc phải một ngoại lệ chung chung. Thay vào đó, bạn sẽ chỉ muốn bắt những từ cụ thể, chẳng hạn như FileNotFoundExceptionhoặc IOExceptionbởi vì chúng có thể có nghĩa khác nhau.


3

Có một tình huống cụ thể mà chúng tôi không thể sử dụng ném, chúng tôi phải sử dụng thử bắt. Có một quy tắc "Một phương thức bị ghi đè không thể ném thêm bất kỳ ngoại lệ nào ngoài những gì lớp cha của nó đang ném". Nếu có thêm bất kỳ ngoại lệ nào cần được xử lý bằng cách sử dụng try-catch. Hãy xem xét đoạn mã này. Có một lớp cơ sở đơn giản

package trycatchvsthrows;

public class Base {
    public void show()
    {
        System.out.println("hello from base");
    }
}

và nó là lớp dẫn xuất:

package trycatchvsthrows;

public class Derived extends Base {

    @Override
    public void show()   {
        // TODO Auto-generated method stub
        super.show();

        Thread thread= new Thread();
        thread.start();
        try {
            thread.sleep(100);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        // thread.sleep(10);
        // here we can not use public void show() throws InterruptedException 
        // not allowed
    }
}

Khi chúng ta phải gọi thread.sleep (), chúng ta buộc phải sử dụng try-catch, ở đây chúng ta không thể sử dụng:

 public void show() throws InterruptedException

bởi vì phương thức ghi đè không thể ném thêm ngoại lệ.


Tôi tin rằng không phải ai cũng nhận thức được điều này. Cũng chỉ.
ivanleoncz

1

Tôi giả định rằng bằng "giống hệt" bạn đang đề cập đến hành vi.

Hành vi của một hàm có thể được xác định bởi:

1) Giá trị trả về

2) Ném ngoại lệ

3) Tác dụng phụ (tức là những thay đổi trong heap, hệ thống tệp, v.v.)

Trong trường hợp này, phương thức đầu tiên truyền bất kỳ ngoại lệ nào, trong khi phương thức thứ hai không ném ra ngoại lệ đã được kiểm tra và nuốt hầu hết các ngoại lệ chưa được kiểm tra, vì vậy hành vi là khác nhau.

Tuy nhiên, nếu bạn đảm bảo rằng "do something" không bao giờ ném ngoại lệ, thì hành vi sẽ giống hệt nhau (mặc dù trình biên dịch sẽ yêu cầu người gọi xử lý ngoại lệ, trong phiên bản đầu tiên)

--biên tập--

Từ quan điểm của thiết kế API, các phương pháp hoàn toàn khác nhau trong hợp đồng của họ. Ngoài ra, việc ném Exception của lớp không được khuyến khích. Hãy thử ném một cái gì đó cụ thể hơn để cho phép người gọi xử lý ngoại lệ tốt hơn.


1

Nếu bạn ném một ngoại lệ, phương thức con (ghi đè điều này) sẽ xử lý ngoại lệ

thí dụ:

class A{
public void myMethod() throws Exception{
 //do something
}
}

A a=new A();
try{
a.myMethod();
}catch Exception(e){
//handle the exception
}

0

Nhiều khi bạn muốn người gọi xử lý ngoại lệ. Giả sử bạn có người gọi gọi một phương thức gọi phương thức khác gọi phương thức khác, thay vì mỗi phương thức xử lý ngoại lệ, bạn chỉ có thể xử lý nó tại trình gọi. Trừ khi, bạn muốn thực hiện điều gì đó trong một trong các phương pháp khi phương pháp đó không thành công.


0

Người gọi phương thức này sẽ cần phải bắt ngoại lệ này hoặc khai báo nó sẽ được phát triển lại trong chữ ký phương thức của nó.

private void calculateArea() throws Exception {
    // Do something
}

Trong ví dụ về khối try-catch bên dưới. Người gọi phương thức này không phải lo lắng về việc xử lý ngoại lệ vì nó đã được xử lý.

private void calculateArea() {
    try {
        // Do something

    } catch (Exception e) {
        showException(e);
    }
}

0
private void calculateArea() throws Exception {
    ....do something
}

Điều này ném ra ngoại lệ, vì vậy người gọi có trách nhiệm xử lý ngoại lệ đó nhưng nếu người gọi không xử lý ngoại lệ thì có thể nó sẽ được cấp cho jvm, điều này có thể dẫn đến kết thúc bất thường của chương trình.

Trong khi ở trường hợp thứ hai:

private void calculateArea() {
    try {
        ....do something
    } catch (Exception e) {
        showException(e);
    }
}

Ở đây ngoại lệ được xử lý bởi callee, vì vậy không có khả năng kết thúc chương trình bất thường.

Thử bắt là cách tiếp cận được khuyến khích.

IMO,

  • Từ khóa Throws chủ yếu được sử dụng với các ngoại lệ Checked để thuyết phục trình biên dịch nhưng nó không đảm bảo kết thúc chương trình bình thường.

  • Từ khóa ném ủy quyền trách nhiệm xử lý ngoại lệ cho
    người gọi (JVM hoặc phương thức khác).

  • Từ khóa ném chỉ được yêu cầu cho các ngoại lệ đã kiểm tra, đối với các ngoại lệ không được kiểm tra, không sử dụng từ khóa né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.