Saya baru saja menemukan beberapa kode indah di aplikasi perusahaan kami yang menggunakan blok Try-Catch sebagai operator logis.
Berarti, "lakukan beberapa kode, jika itu melempar kesalahan ini, lakukan kode ini, tetapi jika itu melempar kesalahan ini lakukan hal ke-3 ini sebagai gantinya".
Ini menggunakan "Akhirnya" sebagai pernyataan "lain" yang muncul.
Saya tahu bahwa ini salah secara inheren, tetapi sebelum saya pergi bertengkar saya berharap untuk beberapa argumen yang dipikirkan dengan matang.
Dan hei, jika Anda memiliki argumen untuk penggunaan Try-Catch dengan cara ini, mohon beri tahu.
Bagi siapa pun yang bertanya-tanya, bahasanya adalah C # dan kode yang dimaksud adalah sekitar 30+ baris dan sedang mencari pengecualian spesifik, itu tidak menangani SEMUA pengecualian.
sumber
try
. Tidak setiap kasus pengecualian yang menuntut pengecualian pada umumnya harus berakibat fatal dalam kasus khusus ini. Jadi, dapatkah Anda melakukannya dengan cara yang lebih sederhana, sama atau lebih kuat tanpa menggunakan pengecualian?Jawaban:
Penanganan pengecualian cenderung menjadi cara yang mahal untuk menangani kontrol aliran (tentu untuk C # dan Java).
Runtime bekerja cukup banyak ketika objek pengecualian dikonstruksi - mendapatkan jejak stack bersama-sama, mencari tahu di mana pengecualian ditangani dan banyak lagi.
Semua ini menghabiskan sumber daya memori dan CPU yang tidak perlu diperluas jika pernyataan kontrol aliran digunakan untuk kontrol aliran.
Selain itu, ada masalah semantik. Pengecualian untuk situasi luar biasa, bukan untuk kontrol aliran normal. Seseorang harus menggunakan penanganan pengecualian untuk menangani situasi yang tidak terduga / luar biasa, tidak seperti aliran program normal, karena jika tidak, pengecualian yang tidak tertangkap akan memberi tahu Anda jauh lebih sedikit.
Terlepas dari dua ini, ada masalah orang lain membaca kode. Menggunakan pengecualian dengan cara seperti itu bukanlah sesuatu yang sebagian besar programmer akan harapkan, jadi keterbacaan dan bagaimana dimengerti kode Anda menderita. Ketika seseorang melihat "Pengecualian", orang berpikir - sesuatu yang buruk terjadi, sesuatu yang tidak seharusnya terjadi secara normal. Jadi, menggunakan pengecualian dengan cara ini benar-benar membingungkan.
sumber
Bagaimana Anda tahu bahwa? Saya menyerahkan semua "pengetahuan" semacam itu dan sekarang hanya percaya bahwa kode yang paling sederhana adalah yang terbaik. Misalkan Anda ingin mengonversi string ke Opsional yang kosong jika parse gagal. Tidak ada yang salah dengan:
Saya sepenuhnya tidak setuju dengan interpretasi biasa "Pengecualian untuk kondisi luar biasa". Ketika suatu fungsi tidak dapat mengembalikan nilai yang dapat digunakan atau metode tidak dapat memenuhi kondisi pasca-nya, berikan pengecualian. Tidak masalah seberapa sering pengecualian ini dilemparkan sampai ada masalah kinerja yang ditunjukkan.
Pengecualian menyederhanakan kode, dengan memungkinkan pemisahan penanganan kesalahan dari aliran normal. Cukup tulis kode yang paling sederhana, dan jika lebih mudah menggunakan try-catch atau melempar pengecualian, maka lakukan itu.
Pengecualian menyederhanakan pengujian dengan mengurangi jumlah jalur melalui kode. Fungsi tanpa cabang akan melengkapi atau melempar pengecualian. Fungsi dengan banyak
if
pernyataan untuk memeriksa kode kesalahan memiliki banyak jalur yang memungkinkan. Sangat mudah untuk mendapatkan salah satu kondisi yang salah, atau melupakan sepenuhnya, sehingga beberapa kondisi kesalahan diabaikan.sumber
int i; if(long.TryParse(s, out i)) return i; else return null;
. TryParse mengembalikan false jika string tidak dapat diuraikan. Jika itu dapat diuraikan itu menetapkan argumen output ke hasil penguraian dan mengembalikan true. Tidak ada pengecualian terjadi, (bahkan secara internal di TryParse) dan terutama tidak ada pengecualian dari jenis yang berarti kesalahan programmer, seperti .NETsFormatException
selalu menunjukkan.Pekerjaan debug dan pemeliharaan sangat sulit ketika aliran kontrol dilakukan dengan menggunakan pengecualian.
Secara inheren, pengecualian dirancang untuk menjadi mekanisme untuk mengubah aliran kontrol normal program Anda - melakukan aktivitas yang tidak biasa, menyebabkan efek samping yang tidak biasa, sebagai cara untuk keluar dari ikatan yang sangat ketat yang tidak dapat ditangani dengan lebih mudah. cara. Pengecualian luar biasa. Ini berarti bahwa, tergantung pada lingkungan mana Anda bekerja, penggunaan pengecualian untuk aliran kontrol reguler dapat menyebabkan:
Inefisiensi Lingkaran tambahan yang harus dilompati oleh lingkungan untuk melakukan perubahan konteks yang relatif sulit secara aman yang diperlukan untuk pengecualian memerlukan instrumentasi dan sumber daya.
Kesulitan debug Kadang-kadang informasi yang berguna (ketika mencoba men-debug suatu program) dikeluarkan dari jendela ketika pengecualian terjadi. Anda bisa kehilangan jejak status program atau riwayat yang relevan untuk memahami perilaku run-time
Masalah perawatan Alur eksekusi sulit ditindaklanjuti melalui lompatan pengecualian. Di luar itu, pengecualian dapat dilempar dari dalam kode jenis kotak hitam, yang mungkin tidak berperilaku mudah dimengerti saat melempar pengecualian.
Keputusan desain yang buruk Program yang dibangun dengan cara ini mendorong kerangka berpikir yang, dalam banyak kasus, tidak mudah dipetakan untuk menyelesaikan masalah secara elegan. Kompleksitas program akhir membuat programmer tidak memahami sepenuhnya pelaksanaannya, dan mendorong pengambilan keputusan yang mengarah pada perbaikan jangka pendek dengan biaya jangka panjang yang tinggi.
sumber
Saya telah melihat pola ini digunakan beberapa kali.
Ada 2 masalah utama:
goto
. Lompatan dianggap berbahaya, karena sejumlah alasan. Mereka harus digunakan, jika semua alternatif memiliki banyak kerugian. Bahkan, dalam semua kode saya, saya hanya ingat 2 kasus, di mana lompatan jelas merupakan solusi terbaik.sumber
Terkadang pengecualian paling cepat. Saya telah melihat kasus di mana pengecualian objek nol lebih cepat bahkan di Jawa daripada menggunakan struktur kontrol (saya tidak bisa mengutip studi saat ini, jadi Anda harus percaya padaku). Masalahnya muncul ketika Java harus benar-benar meluangkan waktu dan mengisi jejak stack kelas pengecualian kustom alih-alih menggunakan yang asli (yang tampaknya setidaknya sebagian di-cache). Sebelum mengatakan bahwa ada sesuatu yang secara sepihak lebih cepat atau lebih lambat, ada baiknya untuk membandingkan.
Dalam Python tidak hanya lebih cepat, tetapi jauh lebih benar untuk melakukan sesuatu yang dapat menyebabkan pengecualian dan kemudian menangani kesalahan. Ya, Anda dapat menerapkan sistem tipe, tetapi itu bertentangan dengan filosofi bahasa - alih-alih Anda hanya perlu mencoba memanggil metode dan menangkap hasilnya! (Menguji apakah suatu file dapat ditulisi mirip - coba tuliskan dan tangkap kesalahannya).
Saya telah melihat saat-saat lebih cepat melakukan sesuatu yang bodoh seperti tabel kueri yang tidak ada di sana daripada mencari tahu apakah sebuah tabel ada di PHP + MySQL ( pertanyaan di mana saya membuat tolok ukur ini adalah satu-satunya jawaban yang diterima dengan suara negatif) .
Semua itu mengatakan, penggunaan pengecualian harus dibatasi karena beberapa alasan:
try...catch
penganut aliran kontrol umumnya (menurut pengalaman saya) tidak mengikuti filosofi "meminimalkan kode dalam blok coba".else if
blok. Cukup berkata (dan jika seseorang membalas dengan "Tapi mereka bisa menggunakan kelas pengecualian yang berbeda", respons saya adalah "Pergi ke kamar Anda dan jangan keluar sampai Anda memikirkan apa yang Anda katakan.")Exception
, ke seluruh dunia (seperti tidak menganuttry...catch
filosofi aliran kontrol), berarti sesuatu telah memasuki keadaan yang tidak stabil (meskipun mungkin dapat dipulihkan). Keadaan yang tidak stabil adalah BURUK dan itu harus membuat kita semua terjaga di malam hari jika kita benar-benar memiliki pengecualian yang dapat dihindari (itu benar-benar membuatku takut, tidak bohong).try...catch
control-flow bertentangan dengan apa yang umumnya dianggap praktik terbaik. Ini berarti dibutuhkan lebih banyak waktu bagi seseorang yang baru dalam suatu proyek untuk mempelajari proyek tersebut, yang berarti peningkatan jumlah jam kerja tanpa hasil sama sekali.try{ obj.openSomething(); /*something which causes exception*/ obj.doStuff(); obj.closeSomething();}catch(Exception e){obj.closeSomething();}
. Dalamif...else
skenario yang lebih tradisional,closeSomething()
kemungkinannya kecil (sekali lagi, pengalaman pribadi) menjadi pekerjaan salin dan tempel. (Harus diakui, argumen khusus ini lebih berkaitan dengan orang-orang yang saya temui daripada filsafat itu sendiri).sumber
Argumen utama saya adalah bahwa menggunakan try / catch for logic memecah aliran logis. Mengikuti "logika" melalui konstruksi non-logika adalah (bagi saya) kontra-intuitif dan membingungkan. Saya terbiasa membaca logika saya sebagai "jika Kondisikan maka A lain B". Membaca pernyataan yang sama dengan "Coba tangkapan lalu jalankan B" terasa aneh. Akan lebih aneh lagi jika pernyataan
A
adalah penugasan sederhana, membutuhkan kode tambahan untuk memaksa pengecualian jikacondition
salah (dan melakukan itu mungkin akan memerlukanif
pernyataan-toh).sumber
Nah, hanya soal etiket, sebelum "memulai pertengkaran dengan mereka", seperti yang Anda nyatakan, saya akan bertanya, "Mengapa mereka menggunakan penanganan perkecualian di semua tempat yang berbeda ini?"
Maksud saya, ada beberapa kemungkinan:
... Saya pikir semua ini sama-sama mungkin. Jadi tanyakan saja kepada mereka dengan baik.
sumber
Try Catch seharusnya hanya digunakan untuk penanganan pengecualian. Lebih dari itu, penanganan pengecualian khusus. Tangkapan uji coba Anda seharusnya hanya menangkap pengecualian yang diharapkan, selain itu tidak terbentuk dengan baik. Jika Anda perlu menggunakan tangkapan semua mencoba menangkap, maka Anda mungkin melakukan sesuatu yang salah.
EDIT:
Alasan: Anda dapat berargumen bahwa jika Anda menggunakan try catch sebagai operator bersyarat, Bagaimana Anda akan memperhitungkan pengecualian NYATA?
sumber
catch
klausa yang berbeda dari yang menangkap pengecualian "tidak nyata"?Pengecualian adalah untuk saat hal luar biasa terjadi. Apakah program berfungsi sesuai dengan alur kerja biasa luar biasa?
sumber
Alasan menggunakan pengecualian:
Alasan untuk tidak menggunakan pengecualian:
Pada akhirnya:
Tujuannya adalah menulis kode yang mengkomunikasikan apa yang sedang terjadi. Pengecualian dapat membantu / menghalangi hal itu tergantung pada apa yang dilakukan kode. Coba / tangkap dengan python untuk KeyError pada referensi kamus sempurna (selama Anda tahu bahasa) coba / tangkap untuk KeyError yang sama lima fungsi lapisan jauh itu berbahaya.
sumber
Saya menggunakan try-> catch sebagai kontrol aliran dalam situasi tertentu. Jika logika utama Anda bergantung pada sesuatu yang gagal, tetapi Anda tidak ingin hanya melemparkan pengecualian dan berhenti ... Itulah gunanya mencoba-> catch block. Saya menulis banyak skrip unix server-side unmonitored, dan jauh lebih penting bagi mereka untuk tidak gagal, daripada bagi mereka untuk gagal dengan cantik.
Jadi coba Paket A, dan jika Paket A mati, tangkap dan jalankan dengan Paket B ... Dan jika paket B gagal, gunakan akhirnya untuk memulai Paket C, yang akan memperbaiki salah satu layanan yang gagal di A atau B, atau halaman saya.
sumber
Itu tergantung pada bahasa dan mungkin pada implementasi yang digunakan. Standar dalam C ++ adalah bahwa pengecualian harus disimpan untuk acara yang benar-benar luar biasa. Di sisi lain, dalam Python salah satu pedoman adalah " lebih mudah untuk meminta maaf daripada izin ", sehingga integrasi coba / kecuali blok dalam logika program dianjurkan.
sumber
Ini kebiasaan buruk, tapi saya melakukannya dari waktu ke waktu dengan python. Seperti daripada memeriksa untuk melihat apakah ada file, saya hanya mencoba dan menghapusnya. Jika itu melempar pengecualian, saya menangkap dan terus mengetahui bahwa itu tidak ada. <== (belum tentu benar jika pengguna lain memiliki file tersebut, tetapi saya melakukannya di direktori home pengguna sehingga ini TIDAK HARUS terjadi).
Namun, terlalu sering menggunakannya adalah praktik yang buruk.
sumber
Saya suka cara Apple mendefinisikannya : Pengecualian hanya untuk kesalahan pemrogram dan kesalahan runtime yang fatal. Gunakan kode kesalahan lain. Ini membantu saya untuk memutuskan kapan menggunakannya, berpikir dalam hati, "Apakah ini kesalahan programmer?"
sumber
Ini terdengar seperti menggunakan penanganan pengecualian untuk membangun logika goto di atas bahasa yang tidak memiliki perintah goto.
Karena banyak alasan mengapa logika goto buruk, Anda dapat merujuk ke pertanyaan ini: https://stackoverflow.com/questions/46586/goto-still-considered-harmful
sumber