Perbedaan antara coba / tangkap / lempar dan coba / tangkap (e) / lempar e

103

Apa perbedaan antara

try { }
catch
{ throw; }

dan

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

?

Dan kapan saya harus menggunakan salah satunya?

Karim
sumber

Jawaban:

151

Konstruksi

try { ... }
catch () { ... } /* You can even omit the () here */

try { ... }
catch (Exception e) { ... }

serupa karena keduanya akan menangkap setiap pengecualian yang dilemparkan ke dalam tryblok (dan, kecuali Anda hanya menggunakan ini untuk mencatat pengecualian, harus dihindari ). Sekarang lihat ini:

try { ... }
catch ()
{
    /* ... */
    throw;
}

try { ... }
catch (Exception e)
{
    /* ... */
    throw;
}

try { ... }
catch (Exception e)
{
    /* ... */
    throw e;
}

Blok coba-tangkap pertama dan kedua adalah PERSIS sama, mereka hanya menampilkan kembali pengecualian saat ini, dan pengecualian itu akan mempertahankan "sumber" dan pelacakan tumpukannya.

Blok coba-tangkap ketiga berbeda. Ketika melempar pengecualian, itu akan mengubah sumber dan jejak tumpukan, sehingga akan tampak bahwa pengecualian telah dilemparkan dari metode ini, dari baris itu throw epada metode yang berisi blok coba-tangkap itu.

Mana yang harus Anda gunakan? Itu sangat tergantung pada masing-masing kasus.

Katakanlah Anda memiliki Personkelas dengan .Save()metode yang akan menyimpannya ke dalam database. Katakanlah aplikasi Anda menjalankan Person.Save()metode di suatu tempat. Jika DB Anda menolak untuk menyelamatkan Orang tersebut, maka .Save()akan mengeluarkan pengecualian. Haruskah Anda menggunakan throwatau throw edalam kasus ini? Tergantung.

Yang saya sukai adalah melakukan:

try {
    /* ... */
    person.Save();
}
catch(DBException e) {
    throw new InvalidPersonException(
       "The person has an invalid state and could not be saved!",
       e);
}

Ini harus menempatkan DBException sebagai "Inner Exception" dari pengecualian yang lebih baru yang dibuang. Jadi, saat Anda memeriksa InvalidPersonException ini, pelacakan tumpukan akan berisi info kembali ke metode Simpan (yang mungkin cukup bagi Anda untuk menyelesaikan masalah), tetapi Anda masih memiliki akses ke pengecualian asli jika Anda membutuhkannya.

Sebagai catatan terakhir, ketika Anda mengharapkan pengecualian, Anda harus benar-benar menangkap satu pengecualian spesifik itu, dan bukan umum Exception, yaitu, jika Anda mengharapkan InvalidPersonException, Anda harus memilih:

try { ... }
catch (InvalidPersonException e) { ... }

untuk

try { ... }
catch (Exception e) { ... }

Semoga berhasil!

Bruno Reis
sumber
34

Yang pertama mempertahankan jejak tumpukan sementara yang kedua menyetel ulang. Ini berarti bahwa jika Anda menggunakan pendekatan kedua, pelacakan tumpukan pengecualian akan selalu dimulai dari metode ini dan Anda akan kehilangan jejak pengecualian asli yang dapat menjadi bencana bagi seseorang yang membaca log pengecualian karena dia tidak akan pernah menemukan penyebab asli pengecualian tersebut. .

Pendekatan kedua mungkin berguna ketika Anda ingin menambahkan informasi tambahan ke pelacakan tumpukan tetapi digunakan seperti ini:

try
{
    // do something
}
catch (Exception ex)
{
    throw new Exception("Additional information...", ex);
}

Ada posting blog yang membahas perbedaannya.

Darin Dimitrov
sumber
Nah, itu bagus untuk diketahui!
Myles
jadi mengapa menggunakan yang kedua? apakah lebih baik menggunakan yang pertama saja?
Karim
1
Yang kedua berguna saat Anda perlu memeriksa pengecualian tertentu - OutOfRangeException muncul di benak - atau perlu mencatat pesan, dll. Yang pertama tampaknya adalah pengendali pengecualian karakter pengganti yang mirip dengan mencoba {} catch (...) {} di c ++.
Simpan
1
David, itu hanya berlaku untuk bagian tangkapan (Pengecualian e) . Dan yang terpisah dari throwvs throw e.
Henk Holterman
6

Kamu harus menggunakan

try { }
catch(Exception e)
{ throw }

jika Anda ingin melakukan sesuatu dengan pengecualian sebelum melemparkannya kembali (misalnya, logging). Lemparan sepi mempertahankan jejak tumpukan.

Otávio Décio
sumber
dan apa yang akan terjadi jika saya mengganti "lemparan" di sini dengan "lemparan e"?
Karim
5

Perbedaan antara tangkapan tanpa parameter dan a catch(Exception e)adalah Anda mendapatkan referensi ke pengecualian. Dari framework versi 2, pengecualian tidak terkelola digabungkan dalam pengecualian terkelola, sehingga pengecualian tanpa parameter tidak lagi berguna untuk apa pun.

Perbedaan antara throw;dan throw e;adalah bahwa yang pertama digunakan untuk menampilkan kembali pengecualian dan yang kedua digunakan untuk menampilkan pengecualian yang baru dibuat. Jika Anda menggunakan yang kedua untuk menampilkan kembali pengecualian, itu akan memperlakukannya seperti pengecualian baru dan mengganti semua informasi tumpukan dari tempat awalnya dilemparkan.

Jadi, Anda sebaiknya tidak menggunakan salah satu alternatif dalam pertanyaan tersebut. Anda tidak boleh menggunakan tangkapan tanpa parameter, dan Anda harus menggunakan throw;untuk memunculkan kembali pengecualian.

Selain itu, dalam banyak kasus, Anda harus menggunakan kelas pengecualian yang lebih spesifik daripada kelas dasar untuk semua pengecualian. Anda seharusnya hanya menangkap pengecualian yang Anda antisipasi.

try {
   ...
} catch (IOException e) {
   ...
   throw;
}

Jika Anda ingin menambahkan informasi apa pun saat memunculkan kembali pengecualian, Anda membuat pengecualian baru dengan pengecualian asli sebagai pengecualian dalam untuk menjaga semua informasi:

try {
   ...
} catch (IOException e) {
   ...
   throw new ApplicationException("Some informative error message", e);
}
Guffa
sumber