Lấy lại các ngoại lệ trong Java mà không mất dấu vết ngăn xếp


417

Trong C #, tôi có thể sử dụng throw;câu lệnh để lấy lại một ngoại lệ trong khi lưu giữ dấu vết ngăn xếp:

try
{
   ...
}
catch (Exception e)
{
   if (e is FooException)
     throw;
}

Có cái gì đó như thế này trong Java ( mà không mất dấu vết ngăn xếp ban đầu )?


4
Tại sao bạn nghĩ rằng nó mất stacktrace ban đầu? Cách duy nhất để làm mất nó khi bạn ném someOtherException mới và quên gán nguyên nhân gốc trong hàm tạo hoặc trong initCause ().
akarnokd

4
Tôi tin rằng đây là cách mã hoạt động trong .Net, nhưng tôi không còn tích cực nữa. Có thể đáng để tìm kiếm nó ở đâu đó hoặc chạy thử nghiệm nhỏ.
ripper234

11
ThrowableKhông được sửa đổi bằng cách ném chúng. Để cập nhật theo dõi ngăn xếp, bạn phải gọi fillInStackTrace(). Thuận tiện phương pháp này được gọi trong hàm tạo của a Throwable.
Robert

50
Trong C #, có, throw e;sẽ mất stacktrace. Nhưng không phải trong Java.
Tim Goodman

Một số tài liệu từ Oracle về các trường hợp ngoại lệ với Java 7: Bắt nhiều loại ngoại lệ và lấy lại ngoại lệ với Kiểm tra loại được cải tiến
Guillaume Husta

Câu trả lời:


560
catch (WhateverException e) {
    throw e;
}

sẽ chỉ đơn giản là lấy lại ngoại lệ bạn đã bắt gặp (rõ ràng phương pháp xung quanh phải cho phép điều này thông qua chữ ký của nó, v.v.). Ngoại lệ sẽ duy trì theo dõi ngăn xếp ban đầu.


4
Xin chào, Interrupttedception e đưa ra một thông báo Ngoại lệ chưa được xử lý khi tôi thêm dòng throw e. Không như vậy nếu tôi thay thế nó bằng Exception rộng hơn e. Làm thế nào điều này nên được thực hiện đúng?
James P.

1
@James, tôi chỉ quan sát thấy rằng thông báo sẽ biến mất nếu thêm "ném XxxException" vào khai báo hàm.
shiouming

2
Trong trình biên dịch Java 7 cho việc suy nghĩ lại như vậy là không rõ ràng hơn. Bây giờ nó hoạt động tốt với các ngoại lệ "ném" cụ thể trong phương thức chứa.
Waldemar Wosiński

193
@James Nếu bạn catch(Exception e) { throw e; }sẽ được giải quyết. Nếu bạn catch(InterruptedException ie) { throw ie; }sẽ được xử lý. Theo nguyên tắc thông thường, đừng catch(Exception e)- đây không phải là pokemon và chúng tôi không muốn bắt hết chúng!
corsiKa

3
@corsiKa Không nhất thiết là bạn không muốn "Bắt tất cả", đó chỉ là một trường hợp sử dụng khác. Nếu bạn có một vòng lặp cấp cao hoặc trình xử lý sự kiện (ví dụ: bên trong chuỗi chạy) nếu bạn không nắm bắt được ít nhất RuntimeException và ghi nhật ký, bạn sẽ thường xuyên bỏ lỡ ngoại lệ và âm thầm thoát khỏi vòng lặp quan trọng để làm gì thường là một lần thất bại. Nó cũng thực sự tốt cho chức năng plugin khi bạn không biết mã bổ sung có thể làm gì hoặc ném ... Đối với việc sử dụng từ trên xuống như thế này, ngoại lệ thường không chỉ là một ý tưởng hay mà còn là một cách thực hành tốt nhất.
Bill K

82

Tôi thích:

try
{
    ...
}
catch (FooException fe){
   throw fe;
}
catch (Exception e)
{
    // Note: don't catch all exceptions like this unless you know what you
    // are doing.
    ...
}

6
Chắc chắn thích hợp trong Java để bắt các ngoại lệ cụ thể hơn chung chung và kiểm tra ví dụ. +1
amischiefr

8
-1 bởi vì bạn không bao giờ nên bắt gặp "Ngoại lệ" đơn giản trừ khi bạn biết bạn đang làm gì.
Stroboskop

19
@Stroboskop: đúng, nhưng để trả lời, tốt nhất là sử dụng cùng một mã (tương tự) như trong câu hỏi!
dùng85421

14
Đôi khi bắt tất cả các ngoại lệ là ok. Chẳng hạn như khi bạn đang viết một trường hợp thử nghiệm. Hoặc cho mục đích đăng nhập. Hoặc trong chính nơi không bắt có nghĩa là bị rơi.
John Henckel

1
@JohnHenckel và những người khác: Điểm hợp lệ thụt vào. Tôi đã cập nhật câu hỏi để làm rõ rằng việc bắt Exceptionthường không phải là điều đúng, trong hầu hết các trường hợp (nhưng không phải tất cả).
Per Lundberg

74

Bạn cũng có thể bọc ngoại lệ trong một trường hợp khác VÀ giữ dấu vết ngăn xếp ban đầu bằng cách chuyển vào Ngoại lệ dưới dạng Ném được làm tham số nguyên nhân:

try
{
   ...
}
catch (Exception e)
{
     throw new YourOwnException(e);
}

8
Tôi cũng sẽ tư vấn về việc thêm một tin nhắn bên cạnh, sử dụngthrow new YourOwnException("Error while trying to ....", e);
Julien

đây là những gì tôi đang tìm kiếm, đặc biệt là phiên bản từ bình luận đầu tiên nơi bạn có thể chuyển thông điệp của riêng mình
Csaba

Điều này hiển thị thông báo lỗi chính xác nhưng theo dõi ngăn xếp hiển thị dòng lỗi dưới dạng dòng với 'throw new ....... (e)' không phải là dòng ban đầu gây ra ngoại lệ.
Ashburn RK

22

Trong Java gần như giống nhau:

try
{
   ...
}
catch (Exception e)
{
   if (e instanceof FooException)
     throw e;
}

5
Không, miễn là bạn không khởi tạo một đối tượng Ngoại lệ mới, stacktrace vẫn giữ nguyên.
Mnementh

28
Tôi sẽ thêm một sản phẩm khai thác cụ thể cho FooException
dfa

3
Trong trường hợp cụ thể này, tôi đồng ý, nhưng thêm một sản phẩm khai thác cụ thể có thể không phải là lựa chọn đúng đắn - hãy tưởng tượng bạn có một số mã chung cho tất cả các ngoại lệ và sau đó, đối với một ngoại lệ cụ thể, hãy thử lại.
alves

1
@MarkusLausberg Nhưng cuối cùng cũng không bắt được ngoại lệ.
Robert

Có, nhưng đây không phải là câu hỏi.
Markus Lausberg

14

Trong Java, bạn chỉ cần ném ngoại lệ mà bạn bắt được, throw ethay vì chỉ throw. Java duy trì theo dõi ngăn xếp.


6

một cái gì đó như thế này

try 
{
  ...
}
catch (FooException e) 
{
  throw e;
}
catch (Exception e)
{
  ...
}

5
public int read(byte[] a) throws IOException {
    try {
        return in.read(a);
    } catch (final Throwable t) {
        /* can do something here, like  in=null;  */
        throw t;
    }
}

Đây là một ví dụ cụ thể trong đó phương thức ném một IOException. Các finalphương tiện tchỉ có thể giữ một ngoại lệ được ném từ khối thử. Tài liệu đọc thêm có thể được tìm thấy ở đâyở đây .



3

Dấu vết ngăn xếp được bảo vệ nếu bạn bọc đoạn trích đã bắt vào một ngoại lệ khác (để cung cấp thêm thông tin) hoặc nếu bạn chỉ lấy lại đoạn trích đã bắt.

try{ ... }catch (FooException e){ throw new BarException("Some usefull info", e); }


2

Tôi chỉ gặp một tình huống tương tự trong đó mã của tôi có khả năng đưa ra một số ngoại lệ khác nhau mà tôi chỉ muốn nghĩ lại. Giải pháp được mô tả ở trên không hiệu quả với tôi, bởi vì Eclipse đã nói với tôi rằng điều đó throw e;dẫn đến một ngoại lệ không rõ ràng, vì vậy tôi chỉ làm điều này:

try
{
...
} catch (NoSuchMethodException | SecurityException | IllegalAccessException e) {                    
    throw new RuntimeException(e.getClass().getName() + ": " + e.getMessage() + "\n" + e.getStackTrace().toString());
}

Đã làm cho tôi....:)

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.