Jawaban:
Konstruksi
try { ... }
catch () { ... } /* You can even omit the () here */
try { ... }
catch (Exception e) { ... }
serupa karena keduanya akan menangkap setiap pengecualian yang dilemparkan ke dalam try
blok (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 e
pada metode yang berisi blok coba-tangkap itu.
Mana yang harus Anda gunakan? Itu sangat tergantung pada masing-masing kasus.
Katakanlah Anda memiliki Person
kelas 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 throw
atau throw e
dalam 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!
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.
throw
vs throw e
.
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.
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);
}