Mengapa menggunakan coba ... akhirnya tanpa klausa menangkap?

79

Cara klasik untuk memprogram adalah dengan try ... catch. Kapan pantas digunakan trytanpa catch?

Dalam Python berikut ini tampak legal dan dapat masuk akal:

try:
  #do work
finally:
  #do something unconditional

Namun, kodenya tidak catchapa - apa. Demikian pula orang dapat berpikir di Jawa itu adalah sebagai berikut:

try {
    //for example try to get a database connection
}
finally {
  //closeConnection(connection)
}

Kelihatannya bagus dan tiba-tiba saya tidak perlu khawatir tentang jenis pengecualian, dll. Jika ini praktik yang baik, kapan itu praktik yang baik? Atau, apa alasan mengapa ini bukan praktik yang baik atau tidak sah? (Saya tidak mengkompilasi sumbernya. Saya bertanya tentang hal itu karena itu bisa menjadi kesalahan sintaksis untuk Java. Saya memeriksa bahwa Python pasti mengkompilasi.)

Masalah terkait yang saya temui adalah ini: Saya terus menulis fungsi / metode, pada akhirnya harus mengembalikan sesuatu. Namun, itu mungkin berada di tempat yang tidak boleh dijangkau dan harus menjadi titik kembali. Jadi, bahkan jika saya menangani pengecualian di atas, saya masih kembali NULLatau string kosong di beberapa titik dalam kode yang tidak boleh dijangkau, sering kali merupakan akhir dari metode / fungsi. Saya selalu berhasil merestrukturisasi kodenya sehingga tidak harus return NULL, karena itu kelihatannya seperti kurang dari praktik yang baik.

Niklas Rosencrantz
sumber
4
Di Jawa, mengapa tidak meletakkan pernyataan pengembalian di akhir blok percobaan?
kevin cline
2
Saya sedih karena mencoba .. akhirnya dan mencoba..catch keduanya menggunakan kata kunci coba, selain keduanya dimulai dengan coba mereka 2 konstruk yang sama sekali berbeda.
Pieter B
3
try/catchbukan "cara klasik untuk memprogram." Ini adalah cara klasik C ++ untuk memprogram, karena C ++ tidak memiliki coba / akhirnya membangun yang tepat, yang berarti Anda harus menerapkan perubahan negara yang dijamin reversibel menggunakan peretasan jelek yang melibatkan RAII. Tetapi bahasa OO yang layak tidak memiliki masalah itu, karena mereka memberikan coba / akhirnya. Ini digunakan untuk tujuan yang sangat berbeda dari coba / tangkap.
Mason Wheeler
3
Saya melihatnya banyak dengan sumber daya koneksi eksternal. Anda menginginkan pengecualian tetapi perlu memastikan bahwa Anda tidak meninggalkan koneksi terbuka dll. Jika Anda menangkapnya, Anda hanya akan mengembalikannya ke lapisan berikutnya dalam beberapa kasus.
Rig
4
@MasonWheeler "Jelek" , tolong, jelaskan apa yang buruk dari memiliki objek yang menangani pembersihan itu sendiri?
Baldrickk

Jawaban:

146

Itu tergantung pada apakah Anda dapat menangani pengecualian yang dapat diajukan pada saat ini atau tidak.

Jika Anda dapat menangani pengecualian secara lokal, Anda harus melakukannya, dan lebih baik menangani kesalahan sedekat mungkin dengan kesalahan tersebut.

Jika Anda tidak dapat mengatasinya secara lokal, maka hanya memiliki try / finallyblok sangat masuk akal - dengan asumsi ada beberapa kode yang perlu Anda jalankan terlepas dari apakah metode tersebut berhasil atau tidak. Sebagai contoh (dari komentar Neil ), membuka aliran dan kemudian meneruskan aliran itu ke metode batin untuk dimuat adalah contoh yang sangat baik ketika Anda akan membutuhkan try { } finally { }, menggunakan klausa terakhir untuk memastikan bahwa aliran ditutup terlepas dari keberhasilan atau kegagalan membaca.

Namun, Anda masih memerlukan penangan pengecualian di suatu tempat dalam kode Anda - kecuali jika Anda ingin aplikasi Anda rusak sepenuhnya. Tergantung pada arsitektur aplikasi Anda persis di mana pawang itu.

ChrisF
sumber
8
"dan lebih baik untuk menangani kesalahan sedekat mungkin dengan tempat dimunculkannya." eh, itu tergantung. Jika Anda dapat memulihkan dan masih menyelesaikan misi (untuk berbicara), ya tentu saja. Jika Anda tidak bisa, lebih baik membiarkan pengecualian sampai ke puncak, di mana (kemungkinan) intervensi pengguna akan diperlukan untuk menangani apa yang terjadi.
Will
13
@ akan - itulah sebabnya saya menggunakan ungkapan "mungkin".
ChrisF
8
Jawaban yang bagus, tetapi saya akan menambahkan contoh: Membuka aliran dan meneruskan aliran itu ke metode batin untuk dimuat adalah contoh yang sangat baik tentang kapan Anda akan membutuhkan try { } finally { }, mengambil keuntungan dari akhirnya klausa untuk memastikan aliran pada akhirnya ditutup terlepas dari keberhasilan / kegagalan.
Neil
karena kadang-kadang semua jalan di atas sedekat yang bisa dilakukan
Newtopian
"Hanya mencoba / akhirnya memblokir sangat masuk akal" sedang mencari jawaban ini. terima kasih @ ChrisF
neal
36

The finallyblok digunakan untuk kode yang harus selalu dijalankan, apakah kondisi kesalahan (pengecualian) terjadi atau tidak.

Kode dalam finallyblok dijalankan setelah tryblok selesai dan, jika pengecualian yang tertangkap terjadi, setelah catchblok yang sesuai selesai. Itu selalu dijalankan, bahkan jika pengecualian tanpa tertangkap terjadi di blok tryatau catch.

The finallyblok biasanya digunakan untuk file penutupan, koneksi jaringan, dll yang dibuka di tryblok. Alasannya adalah bahwa file atau koneksi jaringan harus ditutup, apakah operasi yang menggunakan file atau koneksi jaringan itu berhasil atau gagal.

Perawatan harus diambil di finallyblok untuk memastikan bahwa itu tidak dengan sendirinya melemparkan pengecualian. Misalnya, pastikan dua kali lipat untuk memeriksa semua variabel null, dll.

yfeldblum
sumber
8
+1: Ini idiomatis untuk "harus dibersihkan". Sebagian besar penggunaan try-finallydapat diganti dengan withpernyataan.
S.Lott
12
Berbagai bahasa memiliki peningkatan khusus bahasa yang sangat berguna untuk try/finallykonstruksi. C # has using, Python has with, etc.
yfeldblum
5
@yfeldblum - ada perbedaan halus antara usingdan try-finally, karena Disposemetode ini tidak akan dipanggil oleh usingblok jika pengecualian terjadi di IDisposablekonstruktor objek. try-finallymemungkinkan Anda untuk mengeksekusi kode meskipun konstruktor objek melempar pengecualian.
Scott Whitlock
5
@ScottWhitlock: Itu hal yang baik ? Apa yang Anda coba lakukan, memanggil metode pada objek yang tidak dibangun? Itu satu miliar jenis buruk.
DeadMG
1
@DeadMG: Lihat juga stackoverflow.com/q/14830534/18192
Brian
17

Contoh di mana coba ... akhirnya tanpa klausa tangkapan sesuai (dan bahkan lebih, idiomatik ) di Jawa adalah penggunaan Lock dalam paket kunci utilitas bersamaan.

  • Begini caranya dijelaskan dan dibenarkan dalam dokumentasi API (huruf tebal dalam kutipan adalah milik saya):

    ... Tidak adanya penguncian terstruktur-blok menghilangkan pelepasan kunci secara otomatis yang terjadi dengan metode dan pernyataan yang disinkronkan. Dalam kebanyakan kasus, idiom berikut harus digunakan :

     Lock l = ...;
     l.lock();
     try {
         // access the resource protected by this lock
     } finally {
         l.unlock();
     }

    Ketika penguncian dan pembukaan kunci terjadi dalam cakupan yang berbeda, kehati-hatian harus diambil untuk memastikan bahwa semua kode yang dijalankan saat kunci dipegang dilindungi oleh try-akhirnya atau coba-tangkap untuk memastikan bahwa kunci dilepaskan ketika diperlukan .

agas
sumber
Bisakah saya l.lock()mencoba mencoba? try{ l.lock(); }finally{l.unlock();}
RMachnik
1
secara teknis, Anda bisa. Saya tidak meletakkannya di sana karena secara semantik, itu kurang masuk akal. trydalam cuplikan ini dimaksudkan untuk membungkus akses sumber daya, mengapa mencemarinya dengan sesuatu yang tidak terkait dengan itu
nyamuk
4
Anda bisa, tetapi jika l.lock()gagal, finallyblok masih akan berjalan jika l.lock()ada di dalam tryblok. Jika Anda melakukannya seperti yang disarankan nyamuk, finallyblok hanya akan berjalan ketika kita tahu bahwa kunci telah diperoleh.
Wtrmute
12

Pada tingkat dasar catchdan finallyselesaikan dua masalah terkait tetapi berbeda:

  • catch digunakan untuk menangani masalah yang dilaporkan oleh kode yang Anda panggil
  • finally digunakan untuk membersihkan data / sumber daya yang dibuat / dimodifikasi oleh kode saat ini, tidak peduli apakah ada masalah atau tidak

Jadi keduanya terkait entah bagaimana dengan masalah (pengecualian), tapi itu cukup banyak kesamaan mereka.

Perbedaan penting adalah bahwa finallyblok harus dalam metode yang sama di mana sumber daya dibuat (untuk menghindari kebocoran sumber daya) dan tidak dapat diletakkan pada tingkat yang berbeda di tumpukan panggilan.

The catchnamun adalah hal yang berbeda: tempat yang tepat untuk itu tergantung pada di mana Anda benar-benar dapat menangani pengecualian. Tidak ada gunanya menangkap pengecualian di tempat di mana Anda tidak bisa berbuat apa-apa, karena itu terkadang lebih baik membiarkannya saja.

Joachim Sauer
sumber
2
Nitpick: "... blok akhirnya harus dalam metode yang sama di mana sumber daya dibuat ..." . Tentu saja merupakan ide yang baik untuk melakukannya, karena lebih mudah untuk melihat tidak ada kebocoran sumber daya. Namun, itu bukan prasyarat yang diperlukan; yaitu Anda tidak harus melakukannya dengan cara itu. Anda dapat melepaskan sumber daya dalam finallypernyataan coba terlampir (secara statis atau dinamis) ... dan masih 100% anti bocor.
Stephen C
6

@yfeldblum memiliki jawaban yang benar: coba-akhirnya tanpa pernyataan tangkap biasanya harus diganti dengan konstruksi bahasa yang sesuai.

Di C ++, ia menggunakan RAII dan konstruktor / destruktor; dalam Python itu adalah withpernyataan; dan di C #, itu adalah usingpernyataan.

Ini hampir selalu lebih elegan karena kode inisialisasi dan finalisasi berada di satu tempat (objek abstrak) daripada di dua tempat.

Neil G
sumber
2
Dan di Jawa itu adalah blok ARM
MarkJ
2
Misalkan Anda memiliki objek yang dirancang dengan buruk (Misalnya, objek yang tidak menerapkan IDisposable dalam C #) yang tidak selalu merupakan opsi yang layak.
mootinator
1
@ bootinator: tidak bisakah Anda mewarisi dari objek yang dirancang dengan buruk dan memperbaikinya?
Neil G
2
Atau enkapsulasi? Bah Maksudku, tentu saja.
mootinator
4

Dalam banyak bahasa finallypernyataan juga berjalan setelah pernyataan kembali. Ini berarti Anda dapat melakukan sesuatu seperti:

try {
  // Do processing
  return result;
} finally {
  // Release resources
}

Yang melepaskan sumber daya terlepas dari bagaimana metode itu berakhir dengan pengecualian atau pernyataan pengembalian reguler.

Apakah ini baik atau buruk masih bisa diperdebatkan, tetapi try {} finally {}tidak selalu terbatas pada penanganan pengecualian.

Kamiel Wanrooij
sumber
0

Saya mungkin memohon kemarahan Pythonistas (tidak tahu karena saya tidak banyak menggunakan Python) atau programmer dari bahasa lain dengan jawaban ini, tetapi menurut saya sebagian besar fungsi seharusnya tidak memiliki catchblok, idealnya berbicara. Untuk menunjukkan alasannya, izinkan saya membandingkan ini dengan propagasi kode kesalahan manual seperti yang harus saya lakukan ketika bekerja dengan Turbo C di akhir tahun 80an dan awal tahun 90an.

Jadi katakanlah kita memiliki fungsi untuk memuat gambar atau sesuatu seperti itu sebagai respons terhadap pengguna yang memilih file gambar untuk dimuat, dan ini ditulis dalam C dan assembly:

masukkan deskripsi gambar di sini

Saya menghilangkan beberapa fungsi tingkat rendah tetapi kita dapat melihat bahwa saya telah mengidentifikasi berbagai kategori fungsi, kode warna, berdasarkan pada tanggung jawab apa yang mereka miliki sehubungan dengan penanganan kesalahan.

Titik Kegagalan dan Pemulihan

Sekarang tidak pernah sulit untuk menulis kategori fungsi yang saya sebut "kemungkinan titik kegagalan" (fungsi yang throw, yaitu) dan fungsi "pemulihan kesalahan dan melaporkan" (fungsi yang catch, yaitu).

Fungsi-fungsi yang selalu sepele untuk menulis dengan benar sebelum penanganan pengecualian adalah tersedia sejak fungsi yang bisa lari ke kegagalan eksternal, seperti gagal untuk mengalokasikan memori, hanya bisa mengembalikan NULLatau 0atau -1atau menetapkan kode kesalahan global atau sesuatu untuk efek ini. Dan pemulihan / pelaporan kesalahan selalu mudah karena begitu Anda menelusuri tumpukan panggilan ke titik di mana masuk akal untuk memulihkan dan melaporkan kegagalan, Anda cukup mengambil kode kesalahan dan / atau pesan dan melaporkannya kepada pengguna. Dan tentu saja fungsi di daun hirarki ini yang tidak pernah bisa gagal tidak peduli bagaimana itu berubah di masa depan ( Convert Pixel) sangat sederhana untuk menulis dengan benar (setidaknya sehubungan dengan penanganan kesalahan).

Propagasi Kesalahan

Namun, fungsi-fungsi membosankan yang rentan terhadap kesalahan manusia adalah penyebar kesalahan , yang tidak secara langsung mengalami kegagalan tetapi disebut fungsi yang bisa gagal di suatu tempat yang lebih dalam di hierarki. Pada titik itu, Allocate Scanlinemungkin harus menangani kegagalan dari mallocdan kemudian mengembalikan kesalahan ke Convert Scanlines, kemudian Convert Scanlinesharus memeriksa kesalahan itu dan meneruskannya ke Decompress Image, lalu Decompress Image->Parse Image, dan Parse Image->Load Image, dan Load Imageke perintah pengguna-akhir tempat kesalahan akhirnya dilaporkan .

Di sinilah banyak manusia membuat kesalahan karena hanya membutuhkan satu penyebar kesalahan untuk gagal memeriksa dan meneruskan kesalahan untuk seluruh hierarki fungsi yang akan terguling ketika datang untuk menangani kesalahan dengan benar.

Lebih lanjut, jika kode kesalahan dikembalikan oleh fungsi, kami kehilangan banyak kemampuan dalam, katakanlah, 90% dari basis kode kami, untuk mengembalikan nilai minat pada kesuksesan karena begitu banyak fungsi harus menyimpan nilai pengembaliannya untuk mengembalikan kode kesalahan pada kegagalan .

Mengurangi Kesalahan Manusia: Kode Kesalahan Global

Jadi bagaimana kita bisa mengurangi kemungkinan kesalahan manusia? Di sini saya bahkan mungkin mengundang kemarahan beberapa programmer C, tetapi perbaikan langsung dalam pendapat saya adalah dengan menggunakan kode kesalahan global , seperti OpenGL dengan glGetError. Ini setidaknya membebaskan fungsi untuk mengembalikan nilai-nilai yang menarik dari kesuksesan. Ada cara untuk membuat utas ini aman dan efisien di mana kode kesalahan dilokalkan ke utas.

Ada juga beberapa kasus di mana suatu fungsi mungkin mengalami kesalahan tetapi itu relatif tidak berbahaya untuk itu terus sedikit lebih lama sebelum kembali sebelum waktunya sebagai akibat dari menemukan kesalahan sebelumnya. Hal ini memungkinkan hal seperti itu terjadi tanpa harus memeriksa kesalahan terhadap 90% panggilan fungsi yang dilakukan di setiap fungsi tunggal, sehingga masih dapat memungkinkan penanganan kesalahan yang tepat tanpa begitu teliti.

Mengurangi Kesalahan Manusia: Penanganan Eksepsi

Namun, solusi di atas masih membutuhkan begitu banyak fungsi untuk menangani aspek aliran kontrol propagasi kesalahan manual, bahkan jika itu mungkin telah mengurangi jumlah baris if error happened, return errortipe kode manual . Itu tidak akan menghilangkannya sepenuhnya karena masih sering harus ada setidaknya satu tempat memeriksa kesalahan dan kembali untuk hampir setiap fungsi propagasi kesalahan tunggal. Jadi ini adalah saat penanganan pengecualian muncul untuk menyelamatkan hari (agak).

Tetapi nilai penanganan pengecualian di sini adalah untuk membebaskan kebutuhan untuk berurusan dengan aspek aliran kontrol dari propagasi kesalahan manual. Itu artinya nilainya terikat pada kemampuan untuk menghindari keharusan menulis muatan kapal catchblok sepanjang basis kode Anda. Dalam diagram di atas, satu-satunya tempat yang harus memiliki catchblok adalah Load Image User Commandtempat kesalahan dilaporkan. Tidak ada hal lain yang idealnya harus catchapa - apa karena selain itu mulai membosankan dan rawan kesalahan seperti penanganan kode kesalahan.

Jadi jika Anda bertanya kepada saya, jika Anda memiliki basis kode yang benar-benar mendapat manfaat dari penanganan pengecualian dengan cara yang elegan, itu harus memiliki jumlah minimumcatch blok (minimum saya tidak berarti nol, tetapi lebih seperti satu untuk setiap tinggi yang unik) operasi pengguna akhir yang bisa gagal, dan mungkin bahkan lebih sedikit jika semua operasi pengguna kelas atas dipanggil melalui sistem perintah pusat).

Pembersihan Sumber Daya

Namun, penanganan pengecualian hanya memecahkan kebutuhan untuk menghindari berurusan secara manual dengan aspek aliran kontrol propagasi kesalahan dalam jalur luar biasa terpisah dari aliran eksekusi normal. Seringkali fungsi yang berfungsi sebagai penyebar kesalahan, bahkan jika ia melakukan ini secara otomatis sekarang dengan EH, mungkin masih memperoleh beberapa sumber daya yang perlu dihancurkan. Misalnya, fungsi semacam itu mungkin membuka file sementara yang harus ditutup sebelum kembali dari fungsi apa pun yang terjadi, atau mengunci mutex yang diperlukan untuk membuka kunci apa pun yang terjadi.

Untuk ini, saya mungkin mengundang kemarahan banyak programmer dari semua jenis bahasa, tapi saya pikir pendekatan C ++ untuk ini sangat ideal. Bahasa ini memperkenalkan destruktor yang dapat dipanggil secara deterministik saat instan objek keluar dari ruang lingkup. Karena itu, kode C ++ yang, misalnya, mengunci mutex melalui objek mutex scoped dengan destruktor tidak perlu membukanya secara manual, karena itu akan secara otomatis dibuka setelah objek keluar dari ruang lingkup tidak peduli apa yang terjadi (bahkan jika pengecualian adalah ditemui). Jadi benar-benar tidak perlu kode C ++ yang ditulis dengan baik untuk berurusan dengan pembersihan sumber daya lokal.

Dalam bahasa yang tidak memiliki destruktor, mereka mungkin perlu menggunakan finallyblok untuk membersihkan sumber daya lokal secara manual. Yang mengatakan, itu masih mengalahkan harus membuang sampah sembarangan kode Anda dengan propagasi kesalahan manual asalkan Anda tidak perlu catchpengecualian di seluruh tempat yang menakutkan.

Membalikkan Efek Samping Eksternal

Ini adalah yang masalah konseptual yang paling sulit untuk memecahkan. Jika ada fungsi, apakah itu penyebar kesalahan atau titik kegagalan menyebabkan efek samping eksternal, maka perlu memutar kembali atau "membatalkan" efek samping tersebut untuk mengembalikan sistem kembali ke keadaan seolah-olah operasi tidak pernah terjadi, alih-alih " "setengah valid" ketika operasi separuh berhasil. Saya tahu tidak ada bahasa yang membuat masalah konseptual ini jauh lebih mudah kecuali bahasa yang hanya mengurangi kebutuhan sebagian besar fungsi untuk menyebabkan efek samping eksternal, seperti bahasa fungsional yang berkisar seputar ketidakberdayaan dan struktur data yang persisten.

Berikut finallyini adalah solusi paling elegan di luar sana untuk masalah dalam bahasa yang berputar di sekitar mutabilitas dan efek samping, karena seringkali jenis logika ini sangat spesifik untuk fungsi tertentu dan tidak memetakan dengan baik konsep "pembersihan sumber daya" ". Dan saya sarankan menggunakan finallysecara bebas dalam kasus ini untuk memastikan fungsi Anda membalikkan efek samping dalam bahasa yang mendukungnya, terlepas dari apakah Anda memerlukan catchblok atau tidak (dan lagi, jika Anda bertanya kepada saya, kode yang ditulis dengan baik harus memiliki jumlah minimum catchblok, dan semua catchblok harus berada di tempat yang paling masuk akal dengan diagram di atas Load Image User Command).

Bahasa Impian

Namun, IMO finallysangat ideal untuk pembalikan efek samping tetapi tidak cukup. Kita perlu memperkenalkan satu booleanvariabel untuk secara efektif memutar kembali efek samping dalam kasus keluar prematur (dari pengecualian yang dilemparkan atau sebaliknya), seperti:

bool finished = false;
try
{
    // Cause external side effects.
    ...

    // Indicate that all the external side effects were
    // made successfully.
    finished = true; 
}
finally
{
    // If the function prematurely exited before finishing
    // causing all of its side effects, whether as a result of
    // an early 'return' statement or an exception, undo the
    // side effects.
    if (!finished)
    {
        // Undo side effects.
        ...
    }
}

Jika saya bisa mendesain bahasa, cara impian saya untuk memecahkan masalah ini adalah seperti ini untuk mengotomatiskan kode di atas:

transaction
{
    // Cause external side effects.
    ...
}
rollback
{
    // This block is only executed if the above 'transaction'
    // block didn't reach its end, either as a result of a premature
    // 'return' or an exception.

    // Undo side effects.
    ...
}

... dengan destruktor untuk mengotomatiskan pembersihan sumber daya lokal, membuatnya jadi kita hanya perlu transaction,, rollbackdan catch(meskipun saya mungkin masih ingin menambahkan finally, katakanlah, bekerja dengan sumber daya C yang tidak membersihkan diri sendiri). Namun, finallydengan booleanvariabel adalah hal yang paling dekat untuk membuat ini secara langsung yang saya temukan sejauh ini kurang bahasa mimpi saya. Solusi paling mudah kedua yang saya temukan untuk ini adalah ruang lingkup penjaga dalam bahasa seperti C ++ dan D, tapi saya selalu menemukan ruang lingkup penjaga sedikit canggung secara konseptual karena mengaburkan gagasan "pembersihan sumber daya" dan "pembalikan efek samping". Menurut pendapat saya itu adalah ide yang sangat berbeda untuk ditangani dengan cara yang berbeda.

Mimpi pipa kecil saya tentang bahasa juga akan banyak berputar di sekitar ketidakmampuan dan struktur data yang persisten untuk membuatnya lebih mudah, meskipun tidak diperlukan, untuk menulis fungsi yang efisien yang tidak harus menyalin struktur data besar secara keseluruhan meskipun fungsi menyebabkan tidak ada efek samping.

Kesimpulan

Jadi, dengan mengesampingkan ocehan saya, saya pikir try/finallykode Anda untuk menutup soket baik-baik saja dan bagus mengingat bahwa Python tidak memiliki C ++ yang setara dengan destruktor, dan saya pribadi berpikir Anda harus menggunakannya secara bebas untuk tempat-tempat yang perlu membalikkan efek samping dan meminimalkan jumlah tempat di mana Anda harus catchke tempat-tempat yang paling masuk akal.


sumber
-66

Menangkap kesalahan / pengecualian dan menanganinya dengan cara yang rapi sangat dianjurkan bahkan jika tidak wajib.

Alasan saya mengatakan ini adalah karena saya percaya setiap pengembang harus tahu dan menangani perilaku aplikasinya jika tidak dia tidak menyelesaikan pekerjaannya dengan cara yang sepatutnya. Tidak ada situasi di mana blok coba-akhirnya menggantikan blok coba-tangkap-akhirnya.

Saya akan memberikan Anda contoh sederhana: Asumsikan bahwa Anda telah menulis kode untuk mengunggah file di server tanpa menangkap pengecualian. Sekarang, jika karena suatu alasan unggahan gagal, klien tidak akan pernah tahu apa yang salah. Tetapi, jika Anda telah menangkap pengecualian, Anda dapat menampilkan pesan kesalahan yang menjelaskan apa yang salah dan bagaimana pengguna dapat memperbaikinya.

Aturan emas: Selalu menangkap pengecualian, karena menebak membutuhkan waktu

Pankaj Upadhyay
sumber
22
-1: Di Jawa, klausa terakhir mungkin diperlukan untuk melepaskan sumber daya (mis. Menutup file atau melepaskan koneksi DB). Itu terlepas dari kemampuan untuk menangani pengecualian.
kevin cline
@ kevincline, Dia tidak bertanya apakah akan menggunakan akhirnya atau tidak ... Semua yang dia tanyakan adalah apakah menangkap pengecualian diperlukan atau tidak .... Dia tahu apa yang coba, tangkap dan akhirnya lakukan ..... Akhirnya adalah bagian terpenting, kita semua tahu itu dan mengapa itu digunakan ....
Pankaj Upadhyay
63
@Pankaj: jawaban Anda menunjukkan bahwa catchklausa harus selalu ada setiap kali ada try. Kontributor yang lebih berpengalaman, termasuk saya, percaya ini adalah saran yang buruk. Alasan Anda cacat. Metode yang mengandung trybukan satu-satunya tempat yang mungkin pengecualian dapat ditangkap. Sering kali paling sederhana dan terbaik untuk memungkinkan penangkapan dan melaporkan pengecualian dari tingkat paling atas, daripada menduplikasi klausa tangkapan di seluruh kode.
kevin cline
@ kevincline, saya percaya persepsi pertanyaan di bagian lain agak berbeda. Pertanyaannya adalah tepatnya, Haruskah kita menangkap pengecualian atau tidak .... Dan saya menjawab dalam hal itu. Menangani kekecewaan dapat dilakukan dengan berbagai cara dan bukan hanya sekadar mencoba-akhirnya. Tapi, itu bukan urusan OP. Jika mengajukan pengecualian cukup baik untuk Anda dan orang lain, maka saya harus mengucapkan yang terbaik.
Pankaj Upadhyay
Dengan pengecualian, Anda ingin eksekusi pernyataan normal terputus (dan tanpa memeriksa keberhasilan secara manual pada setiap langkah). Ini khususnya kasus dengan pemanggilan metode bersarang - metode 4 lapisan di dalam beberapa pustaka tidak bisa hanya "menelan" pengecualian; itu perlu dibuang kembali melalui semua lapisan. Tentu saja, setiap lapisan dapat membungkus pengecualian dan menambahkan info tambahan; ini sering tidak dilakukan karena berbagai alasan, waktu tambahan untuk berkembang dan verbositas yang tidak perlu menjadi dua terbesar.
Daniel B