sembari menjaga kode kolega saya bahkan dari seseorang yang mengaku sebagai pengembang senior, saya sering melihat kode berikut:
try
{
//do something
}
catch
{
//Do nothing
}
atau terkadang mereka menulis informasi logging untuk mencatat file seperti try catch
blok berikut
try
{
//do some work
}
catch(Exception exception)
{
WriteException2LogFile(exception);
}
Saya hanya ingin tahu apakah yang telah mereka lakukan adalah praktik terbaik? Itu membuat saya bingung karena dalam pemikiran saya pengguna harus tahu apa yang terjadi dengan sistem.
Tolong beri saya saran.
NullReference
atauArgumentNull
yang bukan bagian dari aliran aplikasi) itu berarti ada bug yang perlu diperbaiki sehingga pencatatannya akan membantu untuk men-debug kode Anda lebih cepat.Jawaban:
Strategi penanganan pengecualian saya adalah:
Untuk menangkap semua pengecualian yang tidak ditangani dengan menghubungkannya ke
Application.ThreadException event
, maka putuskan:Lalu saya selalu menyertakan setiap bagian kode yang dijalankan secara eksternal di
try/catch
:Lalu saya lampirkan di 'coba / tangkap'
ApplicationException("custom message", innerException)
untuk melacak apa yang sebenarnya terjadiSelain itu, saya mencoba yang terbaik untuk mengurutkan pengecualian dengan benar . Ada beberapa pengecualian yang:
finally
bagian saatTreeView
mengisi)pengguna tidak peduli, tetapi penting untuk mengetahui apa yang terjadi. Jadi saya selalu mencatatnya:
Ini adalah praktik yang baik untuk merancang beberapa metode statis untuk menangani pengecualian dalam penangan kesalahan tingkat atas aplikasi.
Saya juga memaksakan diri untuk mencoba:
Jadi akhirnya:
Buruk:
Tak berguna:
Berusaha akhirnya tanpa tangkapan sangat valid:
Apa yang saya lakukan di tingkat atas:
Apa yang saya lakukan dalam beberapa fungsi yang disebut:
Ada banyak yang harus dilakukan dengan penanganan pengecualian (Pengecualian Kustom) tetapi aturan yang saya coba ingat cukup untuk aplikasi sederhana yang saya lakukan.
Berikut adalah contoh metode ekstensi untuk menangani pengecualian yang tertangkap dengan cara yang nyaman. Mereka diimplementasikan dengan cara mereka bisa dirantai bersama, dan sangat mudah untuk menambahkan pemrosesan pengecualian Anda sendiri.
sumber
catch(Exception ex) { throw ex; }
di C # lebih buruk daripada redundan (terlepas dari jenis pengecualian yang Anda tangkap). Untuk rethrow, gunakanthrow;
. Dengan yang pertama, pengecualian akan terlihat seperti itu berasal dari Andathrow ex
sedangkan dengan yang terakhir, itu akan benar berasal darithrow
pernyataan asli .Application.ThreadException
acara dan membungkus setiap pengecualian dengan acatch(Exception ex) {ex.Log(ex);}
. Saya mungkin akan setuju bahwa yang pertama adalah praktik yang sangat baik, tetapi yang terakhir menambahkan risiko menduplikasi log kesalahan Anda dan menyembunyikan bahwa pengecualian terjadi. Jugathrow ex
sangat sangat buruk.Application.ThreadException
acara ini, saya tidak menyadarinya, sangat berguna.Praktik terbaik adalah bahwa penanganan pengecualian tidak boleh menyembunyikan masalah . Ini berarti bahwa
try-catch
blok harus sangat jarang.Ada 3 keadaan di mana menggunakan
try-catch
akal.Selalu berurusan dengan pengecualian yang dikenal serendah mungkin. Namun, jika Anda mengharapkan pengecualian, biasanya praktik yang lebih baik adalah mengujinya terlebih dahulu. Misalnya parse, pengecualian pemformatan dan aritmatika hampir selalu lebih baik ditangani oleh pemeriksaan logika terlebih dahulu, daripada spesifik
try-catch
.Jika Anda perlu melakukan sesuatu dengan pengecualian (misalnya masuk atau memutar kembali suatu transaksi) kemudian lempar kembali pengecualian tersebut.
Selalu berurusan dengan pengecualian yang tidak diketahui setinggi yang Anda bisa - satu - satunya kode yang harus mengkonsumsi pengecualian dan tidak membuangnya haruslah UI atau API publik.
Misalkan Anda terhubung ke API jarak jauh, di sini Anda tahu mengharapkan kesalahan tertentu (dan ada beberapa hal dalam keadaan itu), jadi ini kasus 1:
Perhatikan bahwa tidak ada pengecualian lain yang ditangkap, karena tidak diharapkan.
Sekarang anggaplah Anda mencoba menyimpan sesuatu ke basis data. Kami harus mengembalikannya jika gagal, jadi kami memiliki case 2:
Perhatikan bahwa kami melemparkan kembali pengecualian - kode yang lebih tinggi masih perlu mengetahui bahwa ada sesuatu yang gagal.
Akhirnya kami memiliki UI - di sini kami tidak ingin memiliki pengecualian yang tidak ditangani sepenuhnya, tetapi kami juga tidak ingin menyembunyikannya. Di sini kita memiliki contoh kasus 3:
Namun, sebagian besar kerangka kerja API atau UI memiliki cara generik untuk melakukan kasus 3. Misalnya ASP.Net memiliki layar kesalahan kuning yang membuang detail pengecualian, tetapi itu dapat diganti dengan pesan yang lebih umum di lingkungan produksi. Mengikuti itu adalah praktik terbaik karena menghemat banyak kode, tetapi juga karena kesalahan logging dan tampilan harus merupakan keputusan konfigurasi daripada hard-coded.
Ini semua berarti bahwa case 1 (pengecualian dikenal) dan case 3 (penanganan UI satu kali) keduanya memiliki pola yang lebih baik (menghindari kesalahan yang diharapkan atau penanganan kesalahan hand off ke UI).
Bahkan case 2 dapat diganti dengan pola yang lebih baik, misalnya cakupan transaksi (
using
blok yang mengembalikan transaksi apa pun yang tidak dilakukan selama blok) mempersulit pengembang untuk mendapatkan pola praktik terbaik yang salah.Misalnya, Anda memiliki aplikasi ASP.Net skala besar. Kesalahan logging bisa melalui ELMAH , tampilan kesalahan bisa menjadi YSoD yang informatif secara lokal dan pesan lokal yang bagus dalam produksi. Koneksi basis data semua dapat melalui lingkup dan
using
blok transaksi . Anda tidak perlu satu puntry-catch
blok .TL; DR: Praktik terbaik sebenarnya adalah tidak menggunakan
try-catch
blok sama sekali.sumber
try-catch
- itu bisa (sangat kadang-kadang) berguna dan saya tidak berpendapat bahwa Anda tidak boleh menggunakannya, tetapi 99% dari waktu ada cara yang lebih baik.Pengecualian adalah kesalahan pemblokiran .
Pertama-tama, praktik terbaik seharusnya jangan melemparkan pengecualian untuk segala jenis kesalahan, kecuali itu adalah kesalahan pemblokiran .
Jika kesalahannya memblokir , maka lontarkan pengecualian. Setelah pengecualian dilemparkan, tidak perlu menyembunyikannya karena itu luar biasa; beri tahu pengguna tentang hal itu (Anda harus memformat ulang seluruh pengecualian untuk sesuatu yang berguna bagi pengguna di UI).
Pekerjaan Anda sebagai pengembang perangkat lunak adalah berusaha untuk mencegah kasus luar biasa di mana beberapa parameter atau situasi runtime dapat berakhir dengan pengecualian. Artinya, pengecualian tidak boleh dibisukan, tetapi ini harus dihindari .
Misalnya, jika Anda tahu bahwa beberapa input integer bisa datang dengan format yang tidak valid, gunakan
int.TryParse
sajaint.Parse
. Ada banyak kasus di mana Anda dapat melakukan ini alih-alih hanya mengatakan "jika gagal, cukup lempar pengecualian".Melontarkan pengecualian itu mahal.
Jika, setelah semua, pengecualian dilemparkan, alih-alih menulis pengecualian ke log setelah dilempar, salah satu praktik terbaik adalah menangkapnya di penangan pengecualian kesempatan pertama . Sebagai contoh:
Pendirian saya adalah bahwa percobaan / tangkapan lokal lebih cocok untuk menangani kasus khusus di mana Anda dapat menerjemahkan pengecualian ke kasus lain, atau ketika Anda ingin "membisukan" untuk kasus yang sangat, sangat, sangat, sangat, sangat, sangat istimewa (bug perpustakaan) melempar pengecualian yang tidak terkait yang harus dibisukan untuk menyelesaikan seluruh bug).
Untuk kasus-kasus lainnya:
Menjawab @thewhiteambit pada beberapa komentar ...
@thewhiteambit berkata:
Pertama-tama, bagaimana pengecualian bahkan tidak bisa kesalahan?
null
sementara objek diharapkan => pengecualianKami mungkin mencantumkan 1k kasus ketika pengecualian dilemparkan, dan setelah semua, salah satu kasus yang mungkin akan menjadi kesalahan .
Pengecualian adalah kesalahan, karena pada akhirnya itu adalah objek yang mengumpulkan informasi diagnostik - ia memiliki pesan dan itu terjadi ketika terjadi kesalahan.
Tidak ada yang akan melempar pengecualian ketika tidak ada kasus luar biasa. Pengecualian harus memblokir kesalahan karena begitu mereka dilempar, jika Anda tidak mencoba untuk jatuh ke dalam penggunaan try / catch dan pengecualian untuk menerapkan aliran kontrol itu berarti aplikasi / layanan Anda akan menghentikan operasi yang dimasukkan ke dalam kasus luar biasa .
Juga, saya menyarankan semua orang untuk memeriksa paradigma gagal-cepat yang diterbitkan oleh Martin Fowler (dan ditulis oleh Jim Shore) . Ini adalah bagaimana saya selalu mengerti bagaimana menangani pengecualian, bahkan sebelum saya sampai pada dokumen ini beberapa waktu lalu.
Biasanya pengecualian memotong beberapa aliran operasi dan ditangani untuk mengubahnya menjadi kesalahan yang dapat dipahami manusia. Dengan demikian, sepertinya pengecualian sebenarnya adalah paradigma yang lebih baik untuk menangani kasus kesalahan dan bekerja pada mereka untuk menghindari crash aplikasi / layanan lengkap dan memberi tahu pengguna / konsumen bahwa ada kesalahan.
Jawaban lain tentang masalah @thewhiteambit
Jika aplikasi Anda dapat bekerja offline tanpa menahan data ke basis data, Anda tidak boleh menggunakan pengecualian , karena menerapkan aliran kontrol
try/catch
dianggap sebagai anti-pola. Pekerjaan offline adalah kasus penggunaan yang memungkinkan, jadi Anda menerapkan aliran kontrol untuk memeriksa apakah basis data dapat diakses atau tidak, Anda tidak menunggu sampai tidak terjangkau .Hal parsing juga merupakan kasus yang diharapkan ( bukan KASUS LUAR BIASA ). Jika Anda mengharapkan ini, Anda tidak menggunakan pengecualian untuk melakukan kontrol aliran! . Anda mendapatkan beberapa metadata dari pengguna untuk mengetahui apa budayanya dan Anda menggunakan formatters untuk ini! .NET juga mendukung hal ini dan lingkungan lain, dan pengecualian karena pemformatan angka harus dihindari jika Anda mengharapkan penggunaan khusus aplikasi / layanan Anda .
Artikel ini hanya pendapat atau sudut pandang penulis.
Karena Wikipedia bisa juga hanya pendapat penulis artikel, saya tidak akan mengatakan itu adalah dogma , tetapi periksa apa kata Coding oleh pengecualian artikel di suatu tempat dalam beberapa paragraf:
Ia juga mengatakan di suatu tempat:
Penggunaan pengecualian salah
Jujur, saya percaya bahwa perangkat lunak tidak dapat dikembangkan tidak menganggap serius kasus penggunaan. Jika Anda tahu itu ...
... Anda tidak akan menggunakan pengecualian untuk itu . Anda akan mendukung kasus penggunaan ini menggunakan aliran kontrol biasa.
Dan jika beberapa use case yang tidak terduga tidak tercakup, kode Anda akan gagal dengan cepat, karena itu akan menimbulkan pengecualian . Benar, karena pengecualian adalah kasus luar biasa .
Di sisi lain, dan akhirnya, kadang-kadang Anda menutup kasus luar biasa dengan melempar pengecualian yang diharapkan , tetapi Anda tidak membuangnya untuk menerapkan aliran kontrol. Anda melakukannya karena Anda ingin memberi tahu lapisan atas bahwa Anda tidak mendukung beberapa use case atau kode Anda gagal bekerja dengan beberapa argumen yang diberikan atau data / properti lingkungan.
sumber
Satu-satunya saat Anda harus mengkhawatirkan pengguna Anda tentang sesuatu yang terjadi dalam kode adalah jika ada sesuatu yang dapat atau perlu mereka lakukan untuk menghindari masalah tersebut. Jika mereka dapat mengubah data pada formulir, tekan tombol atau ubah pengaturan aplikasi untuk menghindari masalah lalu beri tahu mereka. Tetapi peringatan atau kesalahan yang tidak bisa dihindari pengguna hanya membuat mereka kehilangan kepercayaan terhadap produk Anda.
Pengecualian dan Log adalah untuk Anda, pengembang, bukan pengguna akhir Anda. Memahami hal yang benar untuk dilakukan ketika Anda menangkap setiap pengecualian jauh lebih baik daripada hanya menerapkan beberapa aturan emas atau mengandalkan jaring pengaman aplikasi-lebar.
Pengodean tanpa pikiran adalah HANYA jenis pengkodean yang salah. Fakta bahwa Anda merasa ada sesuatu yang lebih baik yang dapat dilakukan dalam situasi tersebut menunjukkan bahwa Anda diinvestasikan dalam pengkodean yang baik, tetapi hindari mencoba untuk mencap beberapa aturan umum dalam situasi ini dan memahami alasan sesuatu untuk dilemparkan di tempat pertama dan apa Anda dapat melakukannya untuk memulihkannya.
sumber
Saya tahu ini adalah pertanyaan lama, tetapi tidak ada seorang pun di sini yang menyebutkan artikel MSDN, dan itu adalah dokumen yang benar-benar menjelaskannya bagi saya, MSDN memiliki dokumen yang sangat bagus tentang ini, Anda harus menangkap pengecualian ketika kondisi berikut ini benar:
Saya sarankan membaca seluruh bagian " Pengecualian dan Penanganan Pengecualian " dan juga Praktik Terbaik untuk Pengecualian .
sumber
Pendekatan yang lebih baik adalah yang kedua (yang mana Anda menentukan jenis pengecualian). Keuntungan dari ini adalah Anda tahu bahwa jenis pengecualian ini dapat terjadi dalam kode Anda. Anda menangani jenis pengecualian ini dan Anda dapat melanjutkan. Jika ada pengecualian lain datang, maka itu berarti ada sesuatu yang salah yang akan membantu Anda menemukan bug dalam kode Anda. Aplikasi pada akhirnya akan macet, tetapi Anda akan mengetahui bahwa ada sesuatu yang Anda lewatkan (bug) yang perlu diperbaiki.
sumber
Dengan Pengecualian, saya mencoba yang berikut:
Pertama, saya menangkap jenis pengecualian khusus seperti pembagian dengan nol, operasi IO, dan seterusnya dan menulis kode sesuai dengan itu. Misalnya, pembagian dengan nol, tergantung pada nilai yang dapat saya berikan kepada pengguna (misalnya kalkulator sederhana di mana dalam perhitungan tengah (bukan argumen) tiba di divisi dengan nol) atau untuk diam-diam memperlakukan pengecualian itu, mencatat dan melanjutkan pemrosesan.
Lalu saya mencoba menangkap pengecualian yang tersisa dan mencatatnya. Jika memungkinkan mengizinkan eksekusi kode, jika tidak beri tahu pengguna bahwa ada kesalahan dan minta mereka mengirim laporan kesalahan.
Dalam kode, kira-kira seperti ini:
sumber
0
pembilang sebelumnya, daripada atry-catch
. Juga mengapa menangkap obat generik diException
sini? Anda lebih baik membiarkan gelembung kesalahan naik daripada menghadapinya di sini dalam semua kasus di mana Anda tidak mengharapkannya.Pendekatan kedua adalah yang baik.
Jika Anda tidak ingin menampilkan kesalahan dan membingungkan pengguna aplikasi dengan menunjukkan pengecualian runtime (yaitu kesalahan) yang tidak terkait dengan mereka, maka cukup log kesalahan dan tim teknis dapat mencari masalah dan menyelesaikannya.
Saya sarankan Anda menggunakan pendekatan kedua untuk seluruh aplikasi Anda.
sumber
catch
blokir harus selalu memanggilthrow
untuk menggelembungkan pengecualian ke atas atau mengembalikan sesuatu / menampilkan sesuatu yang memberi tahu pengguna bahwa tindakan telah gagal. Anda ingin mendapatkan panggilan dukungan ketika mereka gagal menyimpan apa pun itu, bukan 6 bulan kemudian ketika mereka mencoba mengambilnya dan tidak dapat menemukannya.Meninggalkan blok tangkapan kosong adalah hal terburuk yang harus dilakukan. Jika ada kesalahan, cara terbaik untuk mengatasinya adalah dengan:
sumber
Bagi saya, menangani pengecualian dapat dilihat sebagai aturan bisnis. Jelas, pendekatan pertama tidak dapat diterima. Yang kedua lebih baik dan mungkin 100% cara yang benar JIKA konteksnya mengatakan demikian. Sekarang, misalnya, Anda sedang mengembangkan Outlook Addin. Jika Anda menambahkan melempar pengecualian yang tidak ditangani, pengguna prospek mungkin sekarang mengetahuinya karena prospek tidak akan menghancurkan dirinya sendiri karena satu plugin gagal. Dan Anda mengalami kesulitan untuk mencari tahu apa yang salah. Oleh karena itu, pendekatan kedua dalam hal ini, bagi saya, itu yang benar. Selain mencatat pengecualian, Anda mungkin memutuskan untuk menampilkan pesan kesalahan kepada pengguna - saya menganggapnya sebagai aturan bisnis.
sumber
Praktik terbaik adalah membuang Pengecualian saat kesalahan terjadi. Karena kesalahan telah terjadi dan tidak boleh disembunyikan.
Tetapi dalam kehidupan nyata Anda dapat memiliki beberapa situasi ketika Anda ingin menyembunyikan ini
sumber
Exception
. Pernah. Lemparkan subkelas yang sesuai dariException
semua yang Anda inginkan, tetapi tidak pernahException
karena itu sama sekali tidak memberikan informasi semantik. Saya benar-benar tidak dapat melihat skenario di mana masuk akal untuk melemparException
tetapi bukan subkelasnya.Anda harus mempertimbangkan Pedoman Desain untuk Pengecualian ini
https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/exceptions
sumber
Yang
catch
tanpa argumen hanyalah memakan pengecualian dan tidak ada gunanya. Bagaimana jika kesalahan fatal terjadi? Tidak ada cara untuk mengetahui apa yang terjadi jika Anda menggunakan tangkapan tanpa argumen.Pernyataan penangkapan harus menangkap Pengecualian yang lebih spesifik seperti
FileNotFoundException
dan kemudian pada akhirnya Anda harus menangkapException
yang akan menangkap pengecualian lain dan mencatatnya.sumber
catch(Exception)
pada akhirnya? Jika Anda tidak mengharapkannya maka itu selalu praktik terbaik untuk meneruskannya ke lapisan berikutnya.Terkadang Anda perlu memperlakukan pengecualian yang tidak mengatakan apa-apa kepada pengguna.
Cara saya adalah:
Ini jelas tidak harus menjadi praktik terbaik. ;-)
sumber
Saya bisa memberitahumu sesuatu:
Cuplikan # 1 tidak dapat diterima karena mengabaikan pengecualian. (Menelannya seperti tidak ada yang terjadi).
Jadi jangan tambahkan catch block yang tidak melakukan apa-apa atau hanya rethrows.
Tangkapan blok harus menambahkan beberapa nilai. Misalnya pesan keluaran untuk pengguna akhir atau kesalahan log.
Jangan gunakan pengecualian untuk logika program aliran normal. Sebagai contoh:
misalnya validasi input. <- Ini bukan situasi luar biasa yang valid, melainkan Anda harus menulis metode
IsValid(myInput);
untuk memeriksa apakah item input valid atau tidak.Kode desain untuk menghindari pengecualian. Sebagai contoh:
Jika kita memberikan nilai yang tidak dapat diuraikan ke int, metode ini akan membuang dan pengecualian, alih-alih kita dapat menulis sesuatu seperti ini:
bool TryParse(string input,out int result);
<- metode ini akan mengembalikan boolean yang menunjukkan jika parse berhasil.Mungkin ini sedikit di luar ruang lingkup pertanyaan ini, tetapi saya harap ini akan membantu Anda untuk membuat keputusan yang tepat ketika itu tentang
try {} catch(){}
dan pengecualian.sumber