Mengapa saya tidak harus membungkus setiap blok di "coba" - "menangkap"?

430

Saya selalu berkeyakinan bahwa jika suatu metode dapat melempar pengecualian maka itu ceroboh untuk tidak melindungi panggilan ini dengan blok percobaan yang bermakna.

Saya baru saja memposting ' Anda harus SELALU membungkus panggilan yang dapat dicoba, tangkap blok. 'untuk pertanyaan ini dan diberi tahu bahwa itu adalah' saran yang sangat buruk '- Saya ingin mengerti mengapa.

Konrad
sumber
4
Jika saya tahu metode akan melempar pengecualian, saya akan memperbaikinya di tempat pertama. Itu karena saya tidak tahu di mana dan mengapa kode akan melempar pengecualian yang saya tangkap di sumbernya (setiap metode - satu try-catch generik). Sebagai contoh, sebuah tim memberi saya basis kode dengan basis data sebelumnya. Banyak kolom yang hilang dan tertangkap hanya setelah menambahkan try catch di lapisan SQL. Kedua saya dapat mencatat nama metode dan pesan, untuk offline debugging-kalau tidak saya tidak tahu dari mana asalnya.
Chakra

Jawaban:

340

Suatu metode seharusnya hanya menangkap pengecualian ketika bisa menanganinya dengan cara yang masuk akal.

Kalau tidak, meneruskannya, dengan harapan metode yang lebih tinggi dari tumpukan panggilan dapat memahaminya.

Seperti yang telah dicatat oleh orang lain, adalah praktik yang baik untuk memiliki penangan pengecualian yang tidak tertangani (dengan logging) di tingkat tertinggi dari tumpukan panggilan untuk memastikan bahwa setiap kesalahan fatal dicatat.

Mitch Wheat
sumber
12
Perlu juga dicatat bahwa ada biaya (dalam hal kode yang dihasilkan) untuk trymemblokir. Ada diskusi yang bagus di "Me C ++ Efektif" dari Scott Meyers.
Nick Meyer
28
Sebenarnya tryblok gratis di kompiler C modern apa pun, informasi itu berasal dari Nick. Saya juga tidak setuju tentang memiliki pengendali pengecualian tingkat atas karena Anda kehilangan informasi lokalitas (tempat sebenarnya di mana instruksi gagal).
Blindy
31
@ Blindly: pengendali pengecualian atas tidak ada untuk menangani pengecualian, tetapi pada kenyataannya berteriak keras bahwa ada pengecualian yang tidak tertangani, berikan pesannya, dan akhiri program dengan cara yang anggun (kembalikan 1 alih-alih panggilan ke terminate) . Ini lebih merupakan mekanisme keamanan. Juga, try/catchlebih atau kurang gratis ketika tidak ada pengecualian. Ketika ada satu propagating, ia menghabiskan waktu setiap kali dilemparkan dan ditangkap, sehingga rantai try/catchyang hanya memikirkan kembali tidak ada biaya.
Matthieu M.
17
Saya tidak setuju Anda harus selalu jatuh pada pengecualian yang tidak tertangkap. Desain perangkat lunak modern sangat terkotak, jadi mengapa Anda harus menghukum sisa aplikasi (dan yang lebih penting, pengguna!) Hanya karena ada satu kesalahan? Menghancurkan hal yang benar-benar terakhir yang ingin Anda lakukan, paling tidak mencoba memberi pengguna sedikit jendela kode yang akan membuat mereka menyimpan pekerjaan bahkan jika sisa aplikasi tidak dapat diakses.
Kendall Helmstetter Gelner
21
Kendall: Jika pengecualian mencapai penangan tingkat atas, aplikasi Anda secara definisi dalam keadaan tidak terdefinisi. Meskipun dalam beberapa kasus tertentu mungkin ada nilai untuk menjaga data pengguna (pemulihan dokumen Word muncul di benak) program tidak boleh menimpa file apa pun atau berkomitmen ke database.
Hugh Brackett
136

Seperti yang dinyatakan oleh Mitch dan yang lainnya , Anda seharusnya tidak menangkap pengecualian bahwa Anda tidak berencana menangani dengan cara tertentu. Anda harus mempertimbangkan bagaimana aplikasi akan menangani pengecualian secara sistematis saat Anda mendesainnya. Ini biasanya mengarah ke memiliki lapisan penanganan kesalahan berdasarkan abstraksi - misalnya, Anda menangani semua kesalahan terkait SQL dalam kode akses data Anda sehingga bagian dari aplikasi yang berinteraksi dengan objek domain tidak terkena fakta bahwa ada adalah DB di bawah tenda di suatu tempat.

Ada beberapa bau kode terkait yang pasti ingin Anda hindari selain bau "tangkap semuanya di mana-mana" .

  1. "catch, log, rethrow" : jika Anda ingin logging berbasis scoped, tulis kelas yang memancarkan pernyataan log dalam destruktornya ketika stack dibuka gulungannya karena pengecualian (ala std::uncaught_exception()). Yang perlu Anda lakukan hanyalah mendeklarasikan instance logging dalam lingkup yang Anda minati dan, voila, Anda telah login dan tidak perlu try/ catchlogika.

  2. "catch, throw diterjemahkan" : ini biasanya menunjuk ke masalah abstraksi. Kecuali jika Anda menerapkan solusi gabungan di mana Anda menerjemahkan beberapa pengecualian spesifik menjadi satu yang lebih umum, Anda mungkin memiliki lapisan abstraksi yang tidak perlu ... dan jangan mengatakan bahwa "Saya mungkin membutuhkannya besok" .

  3. "catch, cleanup, rethrow" : ini adalah salah satu dari kencing binatang peliharaan saya. Jika Anda melihat banyak dari ini, maka Anda harus menerapkan Resource Acquisition is inisialisasi teknik dan menempatkan bagian pembersihan di destruktor dari contoh objek petugas kebersihan .

Saya menganggap kode yang dikotori dengan try/ catchblok menjadi target yang baik untuk tinjauan kode dan refactoring. Ini menunjukkan bahwa penanganan pengecualian tidak dipahami dengan baik atau kode telah menjadi amba dan sangat membutuhkan refactoring.

D.Shawley
sumber
6
# 1 baru bagi saya. +1 untuk itu. Juga, saya ingin mencatat pengecualian umum untuk # 2, yaitu jika Anda mendesain perpustakaan sering kali Anda ingin menerjemahkan pengecualian internal menjadi sesuatu yang ditentukan oleh antarmuka perpustakaan Anda untuk mengurangi penggandengan (ini mungkin maksud Anda oleh "solusi gabungan", tapi saya tidak akrab dengan istilah itu).
rmeador
3
Pada dasarnya apa yang Anda katakan: parashift.com/c++-faq-lite/exceptions.html#faq-17.13
Björn Pollex
1
# 2, di mana itu bukan bau kode tetapi masuk akal, dapat ditingkatkan dengan menjaga pengecualian lama sebagai yang bersarang.
Deduplicator
1
Mengenai # 1: std :: uncaught_exception () memberi tahu Anda bahwa ada pengecualian yang tidak tertangkap dalam penerbangan, tetapi klausa AFAIK hanya tangkapan () memungkinkan Anda menentukan apa pengecualian itu sebenarnya. Jadi, sementara Anda bisa mencatat fakta bahwa Anda keluar dari ruang lingkup karena pengecualian yang tidak tertangkap, hanya mencoba / menangkap terlampir yang memungkinkan Anda mencatat detail apa pun. Benar?
Jeremy
@ Jeremy - Anda benar. Saya biasanya mencatat detail pengecualian ketika saya menangani pengecualian. Memiliki jejak bingkai yang mengintervensi sangat berguna. Anda biasanya perlu mencatat pengenal utas atau konteks pengidentifikasi juga untuk menghubungkan garis log. Saya menggunakan Loggerkelas yang mirip dengan log4j.Loggeryang menyertakan ID utas di setiap baris log dan mengeluarkan peringatan di destruktor ketika pengecualian aktif.
D.Shawley
48

Karena pertanyaan selanjutnya adalah "Saya sudah menangkap pengecualian, apa yang harus saya lakukan selanjutnya?" Apa yang akan kamu lakukan? Jika Anda tidak melakukan apa pun - itu menyembunyikan kesalahan dan program bisa "tidak berfungsi" tanpa ada peluang untuk menemukan apa yang terjadi. Anda perlu memahami apa yang sebenarnya akan Anda lakukan setelah Anda menangkap pengecualian dan hanya menangkap jika Anda tahu.

sharptooth
sumber
29

Anda tidak perlu menutupi setiap blok dengan try-catch karena try-catch masih dapat menangkap pengecualian yang tidak tertangani yang dilemparkan ke fungsi lebih jauh di tumpukan panggilan. Jadi alih-alih setiap fungsi memiliki try-catch, Anda dapat memilikinya di logika tingkat atas aplikasi Anda. Misalnya, mungkin ada SaveDocument()rutinitas tingkat atas, yang memanggil banyak metode yang memanggil metode lain, dll. Sub-metode ini tidak memerlukan tangkapan sendiri, karena jika mereka melempar, itu masih tertangkap oleh SaveDocument()tangkapan.

Ini bagus karena tiga alasan: ini berguna karena Anda memiliki satu tempat untuk melaporkan kesalahan: SaveDocument()blok penangkap. Tidak perlu mengulangi ini di seluruh sub-metode, dan itulah yang Anda inginkan: satu tempat untuk memberi pengguna diagnostik yang berguna tentang sesuatu yang salah.

Dua, simpan dibatalkan setiap kali ada pengecualian. Dengan setiap sub-metode coba-tangkap, jika pengecualian dilemparkan, Anda masuk ke blok tangkap metode itu, eksekusi meninggalkan fungsi, dan terus berjalan SaveDocument(). Jika ada yang salah, Anda mungkin ingin berhenti di sana.

Tiga, semua sub-metode Anda dapat menganggap setiap panggilan berhasil . Jika panggilan gagal, eksekusi akan melompat ke blok tangkap dan kode selanjutnya tidak pernah dieksekusi. Ini dapat membuat kode Anda jauh lebih bersih. Misalnya, ini dengan kode kesalahan:

int ret = SaveFirstSection();

if (ret == FAILED)
{
    /* some diagnostic */
    return;
}

ret = SaveSecondSection();

if (ret == FAILED)
{
    /* some diagnostic */
    return;
}

ret = SaveThirdSection();

if (ret == FAILED)
{
    /* some diagnostic */
    return;
}

Begini caranya yang ditulis dengan pengecualian:

// these throw if failed, caught in SaveDocument's catch
SaveFirstSection();
SaveSecondSection();
SaveThirdSection();

Sekarang jauh lebih jelas apa yang terjadi.

Catatan pengecualian kode aman bisa jadi lebih sulit untuk ditulis dengan cara lain: Anda tidak ingin membocorkan memori apa pun jika ada pengecualian. Pastikan Anda tahu tentang RAII , wadah STL, smart pointer, dan objek lain yang membebaskan sumber dayanya dalam destruktor, karena objek selalu dihancurkan sebelum pengecualian.

AshleysBrain
sumber
2
Contoh bagus. Yup, tangkap setinggi mungkin, dalam unit logis, seperti sekitar beberapa operasi 'transaksional' seperti beban / simpan / dll. Tidak ada yang terlihat lebih buruk daripada kode dibumbui dengan berulang-ulang, berlebihan try- catchblok yang upaya untuk bendera setiap permutasi yang sedikit berbeda dari beberapa error dengan pesan yang sedikit berbeda, walaupun pada kenyataannya mereka semua harus berakhir sama: transaksi atau program gagal dan keluar! Jika terjadi kegagalan layak, saya yakin sebagian besar pengguna hanya ingin menyelamatkan apa yang mereka bisa atau, paling tidak, dibiarkan sendiri tanpa harus berurusan dengan 10 tingkat pesan tentang hal itu.
underscore_d
Hanya ingin mengatakan ini adalah salah satu penjelasan "melempar lebih awal, terlambat" terbaik yang pernah saya baca: ringkas dan contoh-contoh menggambarkan poin Anda dengan sempurna. Terima kasih!
corderazo00
27

Herb Sutter menulis tentang masalah ini di sini . Pasti layak dibaca.
Penggoda:

"Menulis kode pengecualian-aman pada dasarnya tentang menulis 'coba' dan 'tangkap' di tempat yang benar." Bahas.

Terus terang, pernyataan itu mencerminkan kesalahpahaman mendasar tentang keselamatan pengecualian. Pengecualian hanyalah bentuk lain dari pelaporan kesalahan, dan kita tentu tahu bahwa penulisan kode aman kesalahan bukan hanya tentang di mana memeriksa kode pengembalian dan menangani kondisi kesalahan.

Sebenarnya, pengecualian keselamatan jarang tentang menulis 'coba' dan 'menangkap' - dan semakin jarang semakin baik. Juga, jangan pernah lupa bahwa keselamatan pengecualian memengaruhi desain kode; tidak pernah hanya sebuah renungan yang dapat dipasang dengan beberapa pernyataan tangkapan tambahan seolah-olah untuk bumbu.

Tadeusz Kopec
sumber
15

Seperti yang dinyatakan dalam jawaban lain, Anda seharusnya hanya menangkap pengecualian jika Anda bisa melakukan semacam penanganan kesalahan yang masuk akal untuk itu.

Misalnya, dalam pertanyaan yang memunculkan pertanyaan Anda, si penanya menanyakan apakah aman untuk mengabaikan pengecualian untuk lexical_castdari bilangan bulat ke string. Para pemain seperti itu seharusnya tidak pernah gagal. Jika gagal, ada sesuatu yang salah dalam program. Apa yang bisa Anda lakukan untuk pulih dalam situasi itu? Mungkin yang terbaik adalah membiarkan program itu mati, karena ia dalam keadaan yang tidak bisa dipercaya. Jadi tidak menangani pengecualian mungkin merupakan hal paling aman untuk dilakukan.

Kristopher Johnson
sumber
12

Jika Anda selalu menangani pengecualian segera di pemanggil metode yang dapat membuang pengecualian, maka pengecualian menjadi tidak berguna, dan Anda sebaiknya menggunakan kode kesalahan.

Inti dari pengecualian adalah bahwa mereka tidak perlu ditangani dalam setiap metode dalam rantai panggilan.

starblue
sumber
9

Saran terbaik yang pernah saya dengar adalah bahwa Anda seharusnya hanya menangkap pengecualian di titik-titik di mana Anda dapat dengan bijaksana melakukan sesuatu tentang kondisi luar biasa, dan bahwa "menangkap, mencatat, dan melepaskan" bukanlah strategi yang baik (jika kadang-kadang tidak dapat dihindari di perpustakaan).

Donal Fellows
sumber
2
@KeithB: Saya akan menganggapnya sebagai strategi terbaik kedua. Lebih baik jika Anda bisa mendapatkan log yang ditulis dengan cara lain.
David Thornley
1
@KeithB: Ini strategi "lebih baik daripada tidak sama sekali di perpustakaan". "Tangkap, masuk, tangani dengan benar" lebih baik jika memungkinkan. (Ya, saya tahu itu tidak selalu mungkin.)
Donal Fellows
6

Saya setuju dengan arahan dasar pertanyaan Anda untuk menangani sebanyak mungkin pengecualian di tingkat terendah.

Beberapa jawaban yang ada seperti "Anda tidak perlu menangani pengecualian. Orang lain akan melakukannya di tumpukan." Bagi pengalaman saya itu adalah alasan yang buruk untuk tidak memikirkan penanganan pengecualian pada bagian kode yang saat ini dikembangkan, membuat pengecualian menangani masalah orang lain atau lambat.

Masalah itu tumbuh secara dramatis dalam pengembangan terdistribusi, di mana Anda mungkin perlu memanggil metode yang diterapkan oleh rekan kerja. Dan kemudian Anda harus memeriksa rantai panggilan metode bersarang untuk mencari tahu mengapa dia melemparkan beberapa pengecualian pada Anda, yang bisa ditangani lebih mudah pada metode bersarang yang terdalam.

Bananeweizen
sumber
5

Saran yang pernah diberikan profesor sains komputer saya adalah: "Gunakan blok Coba dan Tangkap hanya jika tidak mungkin untuk menangani kesalahan menggunakan cara standar."

Sebagai contoh, dia memberi tahu kami bahwa jika suatu program mengalami masalah serius di tempat yang tidak memungkinkan untuk melakukan sesuatu seperti:

int f()
{
    // Do stuff

    if (condition == false)
        return -1;
    return 0;
}

int condition = f();

if (f != 0)
{
    // handle error
}

Maka Anda harus menggunakan coba, tangkap balok. Meskipun Anda dapat menggunakan pengecualian untuk menangani hal ini, umumnya tidak dianjurkan karena pengecualian adalah kinerja yang bijaksana.

Mike Bailey
sumber
7
Itu adalah salah satu strategi, tetapi banyak orang merekomendasikan untuk tidak pernah mengembalikan kode kesalahan atau status kegagalan / keberhasilan dari fungsi, menggunakan pengecualian. Penanganan kesalahan berbasis pengecualian seringkali lebih mudah dibaca daripada kode berbasis kode kesalahan. (Lihat jawaban AshleysBrain untuk pertanyaan ini sebagai contoh.) Juga, selalu ingat bahwa banyak profesor ilmu komputer memiliki sedikit pengalaman dalam menulis kode sungguhan.
Kristopher Johnson
1
-1 @Sagelika Jawaban Anda terdiri dari menghindari pengecualian, jadi tidak perlu dicoba.
Vicente Botet Escriba
3
@Kristopher: Kelemahan besar lainnya pada kode pengembalian adalah mudah untuk lupa memeriksa kode kembali, dan tepat setelah panggilan tidak selalu merupakan tempat terbaik untuk menangani masalah.
David Thornley
ehh, itu tergantung, tetapi dalam banyak kasus (mengesampingkan orang yang melempar padahal sebenarnya tidak seharusnya), pengecualian lebih baik daripada mengembalikan kode karena berbagai alasan. dalam banyak kasus, gagasan bahwa pengecualian merugikan kinerja adalah hal yang besar '- rujukan]
underscore_d
3

Jika Anda ingin menguji hasil dari setiap fungsi, gunakan kode pengembalian.

Tujuan Pengecualian adalah agar Anda dapat sering menguji hasil KURANG. Idenya adalah untuk memisahkan kondisi yang luar biasa (tidak biasa, lebih jarang) dari kode Anda yang lebih biasa. Ini membuat kode biasa lebih bersih dan sederhana - tetapi masih dapat menangani kondisi luar biasa tersebut.

Dalam kode yang dirancang dengan baik, fungsi yang lebih dalam mungkin dilemparkan dan fungsi yang lebih tinggi mungkin tertangkap. Tetapi kuncinya adalah bahwa banyak fungsi "di antara" akan bebas dari beban menangani kondisi yang luar biasa sama sekali. Mereka hanya harus "pengecualian aman", yang tidak berarti mereka harus menangkap.

bluedog
sumber
2

Saya ingin menambahkan diskusi ini bahwa, sejak C ++ 11 , itu membuat banyak akal, selama setiap catchblok rethrows pengecualian sampai titik itu bisa / harus ditangani. Dengan cara ini backtrace dapat dihasilkan . Karena itu saya percaya pendapat sebelumnya sebagian sudah usang.

Gunakan std::nested_exceptiondanstd::throw_with_nested

Dijelaskan pada StackOverflow di sini dan di sini cara mencapai ini.

Karena Anda bisa melakukan ini dengan kelas pengecualian apa pun, Anda dapat menambahkan banyak informasi ke backtrace tersebut! Anda juga dapat melihat MWE saya di GitHub , di mana backtrace akan terlihat seperti ini:

Library API: Exception caught in function 'api_function'
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"
GPMueller
sumber
2

Saya diberi "kesempatan" untuk menyelamatkan beberapa proyek dan eksekutif menggantikan seluruh tim dev karena aplikasi memiliki terlalu banyak kesalahan dan pengguna sudah bosan dengan masalah dan kehabisan. Semua basis kode ini memiliki penanganan kesalahan terpusat di tingkat aplikasi seperti dijelaskan oleh jawaban terpilih teratas. Jika jawaban itu adalah praktik terbaik mengapa tidak berhasil dan membiarkan tim dev sebelumnya menyelesaikan masalah? Mungkin kadang tidak berhasil? Jawaban di atas tidak menyebutkan berapa lama dev menghabiskan waktu untuk memperbaiki satu masalah. Jika waktu untuk menyelesaikan masalah adalah metrik kunci, menginstruksikan kode dengan try..catch block adalah praktik yang lebih baik.

Bagaimana tim saya memperbaiki masalah tanpa secara signifikan mengubah UI? Sederhana, setiap metode diinstrumentasi dengan try..catch diblokir dan semuanya dicatat pada titik kegagalan dengan nama metode, nilai parameter metode disatukan menjadi string yang diteruskan bersama dengan pesan kesalahan, pesan kesalahan, nama aplikasi, tanggal, dan versi. Dengan informasi ini pengembang dapat menjalankan analitik pada kesalahan untuk mengidentifikasi pengecualian yang paling banyak terjadi! Atau namespace dengan jumlah kesalahan tertinggi. Itu juga dapat memvalidasi bahwa kesalahan yang terjadi dalam modul ditangani dengan benar dan tidak disebabkan oleh beberapa alasan.

Manfaat pro lainnya dari ini adalah pengembang dapat menetapkan satu break-point dalam metode logging kesalahan dan dengan satu break-point dan satu klik tombol debug "step out", mereka berada dalam metode yang gagal dengan akses penuh ke aktual objek pada titik kegagalan, mudah tersedia di jendela langsung. Itu membuatnya sangat mudah untuk debug dan memungkinkan menyeret eksekusi kembali ke awal metode untuk menduplikasi masalah untuk menemukan baris yang tepat. Apakah penanganan pengecualian terpusat memungkinkan pengembang untuk mereplikasi pengecualian dalam 30 detik? Tidak.

Pernyataan "Suatu metode seharusnya hanya menangkap pengecualian ketika dapat menanganinya dengan cara yang masuk akal." Ini menyiratkan bahwa pengembang dapat memprediksi atau akan menghadapi setiap kesalahan yang dapat terjadi sebelum rilis. Jika ini benar tingkat atas, penangan pengecualian aplikasi tidak akan diperlukan dan tidak akan ada pasar untuk Pencarian Elastis dan logstash.

Pendekatan ini juga memungkinkan pengembang menemukan dan memperbaiki masalah berselang dalam produksi! Apakah Anda ingin men-debug tanpa debugger dalam produksi? Atau apakah Anda lebih suka menerima telepon dan menerima email dari pengguna yang kesal? Ini memungkinkan Anda untuk memperbaiki masalah sebelum orang lain tahu dan tanpa harus mengirim email, IM, atau Slack dengan dukungan karena semua yang diperlukan untuk memperbaiki masalah ada di sana. 95% masalah tidak perlu direproduksi.

Agar berfungsi dengan benar, perlu dikombinasikan dengan logging terpusat yang dapat menangkap namespace / modul, nama kelas, metode, input, dan pesan kesalahan dan menyimpannya dalam database sehingga dapat digabungkan untuk menyoroti metode mana yang paling gagal sehingga dapat diperbaiki dulu.

Terkadang pengembang memilih untuk melemparkan pengecualian ke tumpukan dari blok tangkap tetapi pendekatan ini 100 kali lebih lambat dari kode normal yang tidak melempar. Menangkap dan melepaskan dengan logging lebih disukai.

Teknik ini digunakan untuk menstabilkan aplikasi dengan cepat yang gagal setiap jam bagi sebagian besar pengguna di perusahaan Fortune 500 yang dikembangkan oleh 12 Devs selama 2 tahun. Dengan menggunakan 3000 pengecualian ini, diidentifikasi, diperbaiki, diuji, dan digunakan dalam 4 bulan. Ini rata-rata untuk memperbaiki setiap 15 menit rata-rata selama 4 bulan.

Saya setuju bahwa tidak menyenangkan untuk mengetik semua yang diperlukan untuk instrumen kode dan saya lebih suka untuk tidak melihat kode berulang, tetapi menambahkan 4 baris kode untuk setiap metode tidak sia-sia dalam jangka panjang.

pengguna2502917
sumber
1
Membungkus setiap blok sepertinya berlebihan. Dengan cepat membuat kode Anda membengkak dan menyakitkan untuk dibaca. Logout stacktrace dari pengecualian pada level yang lebih tinggi menunjukkan kepada Anda di mana masalah terjadi dan yang dikombinasikan dengan kesalahan itu sendiri umumnya adalah informasi yang cukup untuk melanjutkan. Saya ingin tahu di mana Anda menemukan itu tidak cukup. Supaya aku bisa mendapatkan pengalaman orang lain.
user441521
1
"Pengecualian adalah 100 hingga 1000 kali lebih lambat dari kode normal dan tidak boleh dipikir ulang" - pernyataan itu tidak benar pada kebanyakan kompiler dan perangkat keras modern.
Mitch Wheat
Sepertinya berlebihan dan membutuhkan sedikit pengetikan tetapi merupakan satu-satunya cara untuk melakukan analisis pada pengecualian untuk menemukan dan memperbaiki kesalahan terbesar pertama termasuk kesalahan intermiten dalam produksi. Tangkapan blok menangani kesalahan spesifik jika diperlukan dan memiliki satu baris kode yang mencatat.
user2502917
Tidak, pengecualian sangat lambat. Alternatifnya adalah kode kembali, objek, atau variabel. Lihat posting stack overflow ini ... "pengecualian setidaknya 30.000 kali lebih lambat dari kode pengembalian" stackoverflow.com/questions/891217/…
user2502917
1

Selain saran di atas, secara pribadi saya menggunakan beberapa try + catch + throw; karena alasan berikut:

  1. Pada batas pembuat kode yang berbeda, saya menggunakan try + catch + throw in the code yang ditulis sendiri, sebelum pengecualian dilemparkan ke pemanggil yang ditulis oleh orang lain, ini memberi saya kesempatan untuk mengetahui beberapa kondisi kesalahan yang terjadi pada kode saya, dan tempat ini jauh lebih dekat ke kode yang awalnya membuang pengecualian, semakin dekat, semakin mudah untuk menemukan alasannya.
  2. Pada batas modul, meskipun modul yang berbeda dapat ditulis orang yang sama.
  3. Belajar + Tujuan debug, dalam hal ini saya menggunakan catch (...) di C ++ dan catch (Exception ex) di C #, untuk C ++, pustaka standar tidak membuang terlalu banyak pengecualian, jadi kasus ini jarang terjadi di C ++. Tapi tempat umum di C #, C # memiliki perpustakaan besar dan hierarki pengecualian dewasa, kode perpustakaan C # membuang banyak pengecualian, dalam teori I (dan Anda) harus tahu setiap pengecualian dari fungsi yang Anda panggil, dan tahu alasan / alasan mengapa pengecualian ini dilemparkan, dan tahu cara menanganinya (lewat atau menangkap dan menanganinya di tempat) dengan anggun. Sayangnya pada kenyataannya sangat sulit untuk mengetahui segala sesuatu tentang pengecualian potensial sebelum saya menulis satu baris kode. Jadi saya menangkap semua dan membiarkan kode saya berbicara dengan keras dengan masuk (di lingkungan produk) / menegaskan dialog (di lingkungan pengembangan) ketika ada pengecualian yang benar-benar terjadi. Dengan cara ini saya menambahkan kode penanganan pengecualian secara progresif. Saya tahu itu cocok dengan saran yang bagus tetapi pada kenyataannya itu bekerja untuk saya dan saya tidak tahu cara yang lebih baik untuk masalah ini.
zhaorufei
sumber
1

Saya merasa terdorong untuk menambahkan jawaban lain meskipun jawaban Mike Wheat merangkum poin utama dengan cukup baik. Saya memikirkannya seperti ini. Ketika Anda memiliki metode yang melakukan banyak hal, Anda mengalikan kompleksitas, bukan menambahkannya.

Dengan kata lain, metode yang dibungkus dengan try catch memiliki dua hasil yang mungkin. Anda memiliki hasil non-pengecualian dan hasil pengecualian. Ketika Anda berurusan dengan banyak metode, ini meledak secara eksponensial di luar pemahaman.

Secara eksponensial karena jika setiap metode bercabang dengan dua cara berbeda maka setiap kali Anda memanggil metode lain, Anda mengkuadratkan jumlah hasil potensial sebelumnya. Pada saat Anda telah memanggil lima metode, Anda mencapai 256 kemungkinan hasil minimal. Bandingkan ini dengan tidak melakukan try / catch di setiap metode tunggal dan Anda hanya memiliki satu jalur untuk diikuti.

Pada dasarnya itulah yang saya lihat. Anda mungkin tergoda untuk berpendapat bahwa segala jenis percabangan melakukan hal yang sama tetapi percobaan / tangkapan adalah kasus khusus karena keadaan aplikasi pada dasarnya menjadi tidak terdefinisi.

Jadi singkatnya, coba / tangkap membuat kode jauh lebih sulit untuk dipahami.

pengguna875234
sumber
-2

Anda tidak perlu menutupi setiap bagian dari kode Anda di dalamnya try-catch. Penggunaan utama try-catchblok ini adalah untuk penanganan kesalahan dan mendapat bug / pengecualian dalam program Anda. Beberapa penggunaan try-catch-

  1. Anda dapat menggunakan blok ini di mana Anda ingin menangani pengecualian atau hanya Anda dapat mengatakan bahwa blok kode tertulis dapat melempar pengecualian.
  2. Jika Anda ingin membuang objek Anda segera setelah digunakan, Anda dapat menggunakan try-catchblok.
Amit Kumawat
sumber
1
"Jika kamu ingin membuang benda kamu segera setelah digunakan, kamu dapat menggunakan blok try-catch." Apakah Anda bermaksud ini untuk mempromosikan RAII / objek minimal seumur hidup? Jika demikian, baik, try/ catchadalah completelly terpisah / orthogonal dari itu. Jika Anda ingin membuang objek dalam ruang lingkup yang lebih kecil, Anda bisa membuka yang baru { Block likeThis; /* <- that object is destroyed here -> */ }- tidak perlu membungkus ini di try/ catchkecuali Anda benar-benar perlu catchsesuatu, tentu saja.
underscore_d
# 2 - Membuang objek (yang dibuat secara manual) dengan pengecualian tampak aneh bagi saya, ini dapat berguna dalam beberapa bahasa tidak diragukan lagi, tetapi umumnya Anda melakukannya dalam percobaan / akhirnya "dalam blok coba / kecuali", dan tidak khususnya di blok kecuali itu sendiri - karena objek itu sendiri mungkin menjadi penyebab pengecualian di tempat pertama, dan dengan demikian menyebabkan pengecualian lain dan berpotensi crash.
TS