Rethrowing exception di Java tanpa kehilangan jejak stack


417

Di C #, saya bisa menggunakan throw;pernyataan untuk rethrow pengecualian sambil menjaga jejak stack:

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

Apakah ada sesuatu seperti ini di Jawa ( yang tidak kehilangan jejak tumpukan asli )?


4
Mengapa Anda pikir itu kehilangan stacktrace asli? Satu-satunya cara untuk kehilangan itu ketika Anda melempar SomeOtherException baru dan lupa untuk menetapkan akar penyebab di konstruktor atau di initCause ().
akarnokd

4
Saya percaya ini adalah bagaimana kode berperilaku. Net, tapi saya tidak lagi positif. Mungkin bermanfaat untuk mencarinya di suatu tempat atau menjalankan tes kecil.
ripper234

11
Throwables jangan dimodifikasi dengan melempar mereka. Untuk memperbarui jejak tumpukan, Anda harus menelepon fillInStackTrace(). Mudah metode ini dipanggil dalam konstruktor a Throwable.
Robert

50
Di C #, ya, throw e;akan kehilangan stacktrace. Tetapi tidak di Jawa.
Tim Goodman

Jawaban:


560
catch (WhateverException e) {
    throw e;
}

hanya akan mengubah kembali pengecualian yang Anda tangkap (jelas metode di sekitarnya harus mengizinkan ini melalui tanda tangannya dll.). Pengecualian akan mempertahankan jejak tumpukan asli.


4
Hai, InterruptedException e memberikan pesan Exception yang tidak tertangani ketika saya menambahkan baris throw e. Tidak demikian jika saya menggantinya dengan Pengecualian yang lebih luas e. Bagaimana ini harus dilakukan dengan benar?
James P.

1
@ James, saya baru mengamati bahwa pesannya hilang jika menambahkan "melempar XxxException" dalam deklarasi fungsi.
Shiouming

2
Di Java 7 kompiler untuk rethrow seperti itu lebih cerdas. Sekarang berfungsi dengan baik dengan pengecualian "melempar" khusus dalam metode mengandung.
Waldemar Wosiński

193
@James Jika Anda catch(Exception e) { throw e; }yang akan ditangani. Jika Anda catch(InterruptedException ie) { throw ie; }akan ditangani. Sebagai aturan praktis, jangan catch(Exception e)- ini bukan pokemon, dan kami tidak ingin menangkap mereka semua!
corsiKa

3
@corsiKa Itu tidak selalu benar bahwa Anda tidak ingin "Tangkap mereka semua", itu hanya kasus penggunaan yang berbeda. Jika Anda memiliki loop tingkat atas atau event handler (misalnya, di dalam rangkaian utas) jika Anda tidak menangkap setidaknya RuntimeException dan mencatatnya, Anda akan sering melewatkan pengecualian sama sekali DAN diam-diam keluar dari loop penting untuk apa seringkali merupakan kegagalan satu kali. Ini juga sangat bagus untuk fungsionalitas plugin di mana Anda tidak tahu apa yang mungkin dilakukan atau dibuang oleh kode tambahan ... Untuk penggunaan top-down seperti ini, Pengecualian sering kali bukan hanya merupakan ide bagus tetapi juga praktik terbaik.
Bill K

82

Saya akan lebih memilih:

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
Jelas layak di Jawa untuk menangkap pengecualian khusus daripada generik dan memeriksa misalnya. +1
amischiefr

8
-1 karena Anda seharusnya tidak pernah menangkap "Pengecualian" biasa kecuali Anda tahu apa yang Anda lakukan.
Stroboskop

19
@Stroboskop: true, tetapi untuk menjawabnya lebih baik menggunakan kode yang sama (mirip) seperti dalam pertanyaan!
user85421

14
Terkadang menangkap semua pengecualian tidak masalah. Seperti ketika Anda sedang menulis test case. Atau untuk tujuan logging. Atau di tempat utama di mana tidak menangkap berarti menabrak.
John Henckel

1
@JohnHenckel dan lain-lain: Poin sah yang dimasukkan Saya memperbarui pertanyaan untuk memperjelas bahwa menangkap Exceptionbiasanya bukan hal yang tepat untuk dilakukan, dalam sebagian besar (tetapi tidak semua) kasus.
Per Lundberg

74

Anda juga dapat membungkus pengecualian di yang lain DAN menyimpan jejak tumpukan asli dengan meneruskan Pengecualian sebagai Throwable sebagai parameter penyebab:

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

8
Saya juga menyarankan untuk menambahkan pesan di sampingnya, menggunakanthrow new YourOwnException("Error while trying to ....", e);
Julien

inilah yang saya cari, terutama versi dari komentar pertama di mana Anda dapat menyampaikan pesan Anda sendiri
Csaba

Ini menunjukkan pesan kesalahan dengan benar tetapi jejak stack menunjukkan baris kesalahan sebagai baris dengan 'throw new ....... (e)' bukan baris asli yang menyebabkan pengecualian.
Ashburn RK

22

Di Jawa hampir sama:

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

5
Tidak, selama Anda tidak membuat instance-objek baru stacktrace tetap sama.
Mnementh

28
Saya akan menambahkan tangkapan khusus untuk FooException
dfa

3
Dalam kasus khusus ini saya setuju, tetapi menambahkan tangkapan spesifik mungkin bukan pilihan yang tepat - bayangkan Anda memiliki beberapa kode umum untuk semua pengecualian dan setelah, untuk pengecualian tertentu, kembalikan.
alves

1
@MarkusLausberg Tapi akhirnya tidak menangkap pengecualian.
Robert

Ya, tapi ini bukan pertanyaannya.
Markus Lausberg

14

Di Jawa, Anda hanya melempar pengecualian yang Anda tangkap, jadi throw ebukan hanya throw. Java memelihara jejak stack.


6

sesuatu seperti ini

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;
    }
}

Ini adalah contoh konkret di mana metode melempar IOException. The finalberarti thanya bisa menampung pengecualian dilempar dari blok try. Bahan bacaan tambahan dapat ditemukan di sini dan di sini .



3

Jejak tumpukan di-prserved jika Anda membungkus pengecualian yang ditangkap ke dalam pengecualian lain (untuk memberikan lebih banyak informasi) atau jika Anda hanya memikirkan kembali pengecualian yang ditangkap.

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


2

Saya baru saja mengalami situasi yang sama di mana kode saya berpotensi melempar sejumlah pengecualian berbeda yang hanya ingin saya pikirkan kembali. Solusi yang dijelaskan di atas tidak bekerja untuk saya, karena Eclipse mengatakan kepada saya bahwa throw e;mengarah ke pengecualian yang tidak ditangani, jadi saya hanya melakukan ini:

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

Bekerja untuk saya .... :)

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.