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 )?

ripper234
sumber
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
Beberapa dokumen dari Oracle tentang pengecualian dengan Java 7: Menangkap Banyak Jenis Pengecualian dan Memikirkan Kembali Pengecualian dengan Peningkatan Jenis Pemeriksaan
Guillaume Husta

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.

Brian Agnew
sumber
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.
    ...
}
Markus Lausberg
sumber
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);
}
Olvagor
sumber
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;
}
Alves
sumber
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.

David M.
sumber
6

sesuatu seperti ini

try 
{
  ...
}
catch (FooException e) 
{
  throw e;
}
catch (Exception e)
{
  ...
}
cdeszaq
sumber
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 .

Daniel
sumber
1
Itu tidak harus final. Lihat docs.oracle.com/javase/7/docs/technotes/guides/language/… dan stackoverflow.com/a/6889301/131160
jcsahnwaldt mengatakan GoFundMonica
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); }

Sindre
sumber
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 .... :)

Matthias
sumber