Untuk menghindari semua jawaban standar yang saya bisa gunakan di Google, saya akan memberikan contoh yang Anda semua bisa serang sesuka hati.
C # dan Java (dan terlalu banyak yang lain) miliki dengan banyak tipe beberapa perilaku 'overflow' yang saya tidak suka sama sekali (misalnya misalnya type.MaxValue + type.SmallestValue == type.MinValue
:) int.MaxValue + 1 == int.MinValue
.
Tapi, melihat sifat jahat saya, saya akan menambahkan beberapa penghinaan untuk cedera ini dengan memperluas perilaku ini, katakanlah DateTime
tipe Overridden . (Saya tahu DateTime
disegel dalam. NET, tetapi demi contoh ini, saya menggunakan bahasa semu yang persis seperti C #, kecuali untuk fakta bahwa DateTime tidak disegel).
Add
Metode yang diganti :
/// <summary>
/// Increments this date with a timespan, but loops when
/// the maximum value for datetime is exceeded.
/// </summary>
/// <param name="ts">The timespan to (try to) add</param>
/// <returns>The Date, incremented with the given timespan.
/// If DateTime.MaxValue is exceeded, the sum wil 'overflow' and
/// continue from DateTime.MinValue.
/// </returns>
public DateTime override Add(TimeSpan ts)
{
try
{
return base.Add(ts);
}
catch (ArgumentOutOfRangeException nb)
{
// calculate how much the MaxValue is exceeded
// regular program flow
TimeSpan saldo = ts - (base.MaxValue - this);
return DateTime.MinValue.Add(saldo)
}
catch(Exception anyOther)
{
// 'real' exception handling.
}
}
Tentu saja jika bisa menyelesaikan ini dengan mudah, tetapi kenyataannya tetap saja saya gagal melihat mengapa Anda tidak dapat menggunakan pengecualian (secara logis artinya, saya dapat melihat bahwa ketika kinerja merupakan masalah yang dalam beberapa kasus pengecualian harus dihindari. ).
Saya pikir dalam banyak kasus mereka lebih jelas daripada jika-struktur dan tidak melanggar kontrak apa pun yang dibuat metode ini.
IMHO reaksi "Jangan pernah menggunakannya untuk aliran program reguler" yang tampaknya dimiliki semua orang tidak terlalu buruk karena kekuatan reaksi itu dapat dibenarkan.
Atau saya salah?
Saya sudah membaca posting lain, berurusan dengan semua jenis kasus khusus, tetapi poin saya adalah tidak ada yang salah dengan itu jika Anda berdua:
- Bersih
- Hormati kontrak metode Anda
Tembak saya.
sumber
if
pernyataan yang mendokumentasikan diri sendiri jauh lebih pendek . Anda akan menemukan ini sangat sulit. Dengan kata lain: premis Anda sendiri cacat, dan kesimpulan yang Anda ambil darinya salah.Jawaban:
Pernahkah Anda mencoba men-debug program yang menaikkan lima pengecualian per detik dalam operasi normal?
Saya sudah.
Program ini cukup kompleks (itu adalah server perhitungan terdistribusi), dan sedikit modifikasi di satu sisi program dapat dengan mudah memecahkan sesuatu di tempat yang sama sekali berbeda.
Saya berharap saya bisa saja meluncurkan program dan menunggu pengecualian terjadi, tetapi ada sekitar 200 pengecualian selama permulaan dalam operasi normal
Maksud saya: jika Anda menggunakan pengecualian untuk situasi normal, bagaimana Anda menemukan situasi yang tidak biasa (yaitu pengecualian al)?
Tentu saja, ada alasan kuat lain untuk tidak menggunakan terlalu banyak pengecualian, terutama dari segi kinerja
sumber
Pengecualian pada dasarnya adalah
goto
pernyataan non-lokal dengan semua konsekuensi dari yang terakhir. Menggunakan pengecualian untuk kontrol aliran melanggar prinsip yang paling mengejutkan , membuat program sulit dibaca (ingat bahwa program ditulis untuk programmer terlebih dahulu).Selain itu, ini bukan yang diharapkan oleh vendor kompiler. Mereka mengharapkan pengecualian untuk jarang dilempar, dan mereka biasanya membiarkan
throw
kode menjadi sangat tidak efisien. Melontarkan pengecualian adalah salah satu operasi paling mahal di .NET.Namun, beberapa bahasa (terutama Python) menggunakan pengecualian sebagai konstruk kontrol aliran. Misalnya, iterator memunculkan
StopIteration
pengecualian jika tidak ada item lebih lanjut. Bahkan konstruksi bahasa standar (sepertifor
) mengandalkan ini.sumber
goto
, tentu saja, perkecualian berinteraksi dengan benar dengan tumpukan panggilan Anda dan dengan pelingkupan leksikal, dan jangan meninggalkan tumpukan atau cakupan dalam kekacauan.Aturan praktis saya adalah:
Masalah yang saya lihat dengan pengecualian adalah dari sudut pandang sintaksis murni (saya cukup yakin kinerja overhead minimal). Saya tidak suka blok percobaan di semua tempat.
Ambil contoh ini:
.. Contoh lain bisa terjadi ketika Anda perlu menetapkan sesuatu ke pegangan menggunakan pabrik, dan pabrik itu bisa mengeluarkan pengecualian:
Jadi, secara pribadi, saya pikir Anda harus menyimpan pengecualian untuk kondisi kesalahan yang jarang terjadi (kehabisan memori, dll.) Dan menggunakan nilai balik (kacamata nilai, struct, atau enum) untuk melakukan pengecekan kesalahan.
Semoga saya mengerti pertanyaan Anda dengan benar :)
sumber
Reaksi pertama terhadap banyak jawaban:
Tentu saja! Tetapi jika tidak selalu lebih jelas setiap saat.
Seharusnya tidak mengherankan misalnya: membagi (1 / x) menangkap (pembagianByZero) lebih jelas daripada jika saya (di Conrad dan lain-lain). Fakta pemrograman semacam ini tidak diharapkan murni konvensional, dan memang, masih relevan. Mungkin dalam contoh saya jika akan lebih jelas.
Tapi DivisionByZero dan FileNotFound dalam hal ini lebih jelas daripada seandainya.
Tentu saja jika itu kurang berkinerja dan membutuhkan miliaran waktu per detik, Anda tentu saja harus menghindarinya, tetapi saya masih belum membaca alasan bagus untuk menghindari desain keseluruhan.
Sejauh prinsip yang paling mengejutkan: ada bahaya penalaran melingkar di sini: seandainya seluruh komunitas menggunakan desain yang buruk, desain ini akan menjadi yang diharapkan! Karena itu prinsipnya tidak bisa menjadi cawan dan harus dipertimbangkan dengan hati-hati.
Dalam banyak reaksi, sth. seperti ini bersinar palung. Tangkap saja, bukan? Metode Anda harus jelas, didokumentasikan dengan baik, dan menunggu kontraknya. Saya tidak mendapatkan pertanyaan yang harus saya akui.
Debugging pada semua pengecualian: sama, itu hanya dilakukan kadang-kadang karena desain untuk tidak menggunakan pengecualian adalah umum. Pertanyaan saya adalah: mengapa itu biasa terjadi?
sumber
x
sebelum menelepon1/x
? 2) Apakah Anda membungkus setiap operasi divisi menjadi blok try-catch untuk menangkapDivideByZeroException
? 3) Apa logika yang Anda masukkan ke dalam blok penangkap untuk pulihDivideByZeroException
?openConfigFile();
bisa diikuti oleh FileNotFound yang tertangkap dengan{ createDefaultConfigFile(); setFirstAppRun(); }
pengecualian FileNotFound yang ditangani dengan anggun; tidak crash, mari kita buat pengalaman pengguna akhir lebih baik, tidak lebih buruk. Anda mungkin berkata, "Tetapi bagaimana jika ini bukan benar-benar menjalankan pertama dan mereka mendapatkan itu setiap waktu?" Setidaknya aplikasi berjalan setiap waktu dan tidak menabrak setiap startup! Pada 1-ke-10 "ini mengerikan": "jalankan pertama" setiap startup = 3 atau 4, crash setiap startup = 10.x
sebelum menelepon1/x
, karena biasanya baik-baik saja. Kasus luar biasa adalah kasus di mana itu tidak baik. Kita tidak berbicara tentang penghancuran bumi di sini, tetapi misalnya untuk bilangan bulat dasar yang diberikan secara acakx
, hanya 1 dari 4294967296 yang gagal melakukan pembagian. Itu luar biasa dan pengecualian adalah cara yang baik untuk menghadapinya. Namun, Anda bisa menggunakan pengecualian untuk mengimplementasikan pernyataan yang setaraswitch
, tetapi itu akan sangat konyol.Sebelum pengecualian, di C, ada
setjmp
danlongjmp
yang bisa digunakan untuk menyelesaikan pembukaan gulungan frame stack yang serupa.Kemudian konstruksi yang sama diberi nama: "Pengecualian". Dan sebagian besar jawaban bergantung pada makna nama ini untuk berdebat tentang penggunaannya, mengklaim bahwa pengecualian dimaksudkan untuk digunakan dalam kondisi luar biasa. Itu tidak pernah menjadi maksud dalam aslinya
longjmp
. Hanya ada situasi di mana Anda perlu memutus aliran kontrol di banyak bingkai tumpukan.Pengecualian sedikit lebih umum karena Anda dapat menggunakannya dalam bingkai tumpukan yang sama juga. Ini menimbulkan analogi dengan
goto
yang saya percaya salah. Foto adalah pasangan yang sangat erat (dan begitu jugasetjmp
danlongjmp
). Pengecualian mengikuti publikasi / berlangganan yang digabungkan secara longgar yang jauh lebih bersih! Oleh karena itu menggunakannya dalam bingkai tumpukan yang sama hampir tidak sama dengan menggunakangoto
s.Sumber kebingungan ketiga berhubungan dengan apakah mereka diperiksa atau tidak dicentang pengecualian. Tentu saja, pengecualian yang tidak diperiksa tampaknya sangat mengerikan untuk digunakan untuk aliran kontrol dan mungkin banyak hal lainnya.
Namun, pengecualian yang dicek sangat cocok untuk aliran kontrol, setelah Anda mengatasi semua masalah Victoria dan hidup sedikit.
Penggunaan favorit saya adalah urutan
throw new Success()
dalam fragmen panjang kode yang mencoba satu demi satu sampai menemukan apa yang dicari. Setiap hal - masing-masing bagian dari logika - mungkin bersarang secara acak sehinggabreak
keluar juga segala jenis tes kondisi. Theif-else
pola rapuh. Jika saya mengeditelse
atau mengacaukan sintaks dengan cara lain, maka ada bug berbulu.Menggunakan
throw new Success()
linierisasi aliran kode. Saya menggunakanSuccess
kelas yang didefinisikan secara lokal - diperiksa tentu saja - sehingga jika saya lupa menangkapnya, kode tidak akan dikompilasi. Dan saya tidak menangkapSuccess
es metode lain .Terkadang kode saya memeriksa satu dan lain hal dan hanya berhasil jika semuanya baik-baik saja. Dalam hal ini saya menggunakan linearisasi serupa
throw new Failure()
.Menggunakan fungsi terpisah mengacaukan tingkat alami kompartementalisasi. Jadi
return
solusinya tidak optimal. Saya lebih suka memiliki satu atau dua halaman kode di satu tempat karena alasan kognitif. Saya tidak percaya pada kode yang dibagi sangat halus.Apa yang dilakukan JVM atau kompiler kurang relevan bagi saya kecuali ada hotspot. Saya tidak percaya ada alasan mendasar bagi penyusun untuk tidak mendeteksi Pengecualian yang dilemparkan dan ditangkap secara lokal dan memperlakukannya sebagai sangat efisien
goto
pada tingkat kode mesin.Sejauh menggunakannya di seluruh fungsi untuk aliran kontrol - yaitu untuk kasus umum dan bukan yang luar biasa - Saya tidak bisa melihat bagaimana mereka akan kurang efisien daripada beberapa istirahat, tes kondisi, kembali ke mengarungi tiga frame stack sebagai lawan hanya mengembalikan penunjuk tumpukan.
Saya pribadi tidak menggunakan pola di seluruh bingkai tumpukan dan saya bisa melihat bagaimana itu membutuhkan kecanggihan desain untuk melakukannya dengan elegan. Tetapi jika digunakan dengan hemat, itu tidak masalah.
Terakhir, mengenai programmer perawan yang mengejutkan, itu bukan alasan yang meyakinkan. Jika Anda dengan lembut mengenalkan mereka pada latihan, mereka akan belajar untuk menyukainya. Saya ingat C ++ digunakan untuk mengejutkan dan menakut-nakuti programmer C.
sumber
return
alternatif -pattern akan membutuhkan dua fungsi untuk setiap fungsi tersebut. Yang luar untuk mempersiapkan respon servlet atau tindakan lain seperti itu, dan yang dalam untuk melakukan perhitungan. PS: Seorang profesor bahasa Inggris mungkin akan menyarankan saya menggunakan "mencengangkan" daripada "mengejutkan" dalam paragraf terakhir :-)Server standar adalah pengecualian tidak teratur dan harus digunakan dalam kasus luar biasa.
Salah satu alasan, yang penting bagi saya, adalah bahwa ketika saya membaca
try-catch
struktur kontrol dalam perangkat lunak yang saya kelola atau debug, saya mencoba mencari tahu mengapa pembuat kode asli menggunakan penanganan pengecualian alih-alihif-else
struktur. Dan saya berharap menemukan jawaban yang bagus.Ingatlah bahwa Anda menulis kode tidak hanya untuk komputer tetapi juga untuk pembuat kode lain. Ada semantik yang terkait dengan penangan pengecualian yang tidak dapat Anda buang hanya karena mesin tidak keberatan.
sumber
Bagaimana dengan kinerja? Saat memuat pengujian aplikasi web .NET, kami berhasil mencapai 100 pengguna simulasi per server web hingga kami memperbaiki pengecualian yang biasa terjadi dan jumlahnya meningkat menjadi 500 pengguna.
sumber
Josh Bloch membahas topik ini secara luas di Java Efektif. Sarannya mencerahkan dan harus berlaku untuk Net juga (kecuali untuk rinciannya).
Khususnya, pengecualian harus digunakan untuk keadaan luar biasa. Alasan untuk ini terkait dengan kegunaan, terutama. Agar metode yang diberikan dapat digunakan secara maksimal, kondisi input dan outputnya harus dibatasi secara maksimal.
Misalnya, metode kedua lebih mudah digunakan daripada yang pertama:
Dalam kedua kasus tersebut, Anda perlu memeriksa untuk memastikan bahwa pemanggil menggunakan API Anda dengan tepat. Tetapi dalam kasus kedua, Anda memerlukannya (secara implisit). Pengecualian lunak akan tetap dilemparkan jika pengguna tidak membaca javadoc, tetapi:
Titik permukaan tanah adalah bahwa Pengecualian tidak boleh digunakan sebagai kode pengembalian, sebagian besar karena Anda tidak hanya rumit API ANDA, tetapi API penelepon juga.
Tentu saja melakukan hal yang benar harus dibayar. Biayanya adalah semua orang perlu memahami bahwa mereka perlu membaca dan mengikuti dokumentasi. Semoga itulah masalahnya.
sumber
Saya pikir Anda bisa menggunakan Pengecualian untuk kontrol aliran. Namun, ada sisi negatif dari teknik ini. Membuat Pengecualian adalah hal yang mahal, karena mereka harus membuat jejak tumpukan. Jadi, jika Anda ingin menggunakan Pengecualian lebih sering daripada hanya menandakan situasi yang luar biasa, Anda harus memastikan bahwa membangun jejak tumpukan tidak memengaruhi kinerja Anda secara negatif.
Cara terbaik untuk mengurangi biaya membuat pengecualian adalah dengan mengganti metode fillInStackTrace () seperti ini:
Pengecualian seperti itu tidak akan memiliki stacktraces diisi.
sumber
Saya tidak benar-benar melihat bagaimana Anda mengendalikan aliran program dalam kode yang Anda kutip. Anda tidak akan pernah melihat pengecualian lain selain pengecualian ArgumentOutOfRange. (Jadi klausa tangkapan kedua Anda tidak akan pernah mengenai). Yang Anda lakukan hanyalah menggunakan lemparan yang sangat mahal untuk meniru pernyataan if.
Anda juga tidak melakukan operasi yang lebih menyeramkan di mana Anda hanya melemparkan pengecualian semata-mata untuk ditangkap di tempat lain untuk melakukan kontrol aliran. Anda sebenarnya menangani kasus luar biasa.
sumber
Berikut adalah praktik terbaik yang saya jelaskan di posting blog saya :
sumber
Karena kode ini sulit dibaca, Anda mungkin mengalami masalah saat debugging, Anda akan memperkenalkan bug baru ketika memperbaiki bug setelah waktu yang lama, itu lebih mahal dalam hal sumber daya dan waktu, dan itu mengganggu Anda jika Anda men-debug kode Anda dan debugger menghentikan kemunculan setiap pengecualian;)
sumber
Terlepas dari alasan yang disebutkan, satu alasan untuk tidak menggunakan pengecualian untuk kontrol aliran adalah bahwa hal itu dapat sangat mempersulit proses debugging.
Misalnya, ketika saya mencoba melacak bug di VS saya biasanya akan mengaktifkan "break on all exception". Jika Anda menggunakan pengecualian untuk kontrol aliran maka saya akan melanggar debugger secara teratur dan harus terus mengabaikan pengecualian tidak luar biasa ini sampai saya sampai pada masalah sebenarnya. Ini mungkin membuat seseorang marah !!
sumber
Mari kita asumsikan Anda memiliki metode yang melakukan beberapa perhitungan. Ada banyak parameter input yang harus divalidasi, lalu untuk mengembalikan angka lebih besar dari 0.
Menggunakan nilai kembali ke kesalahan validasi sinyal, itu sederhana: jika metode mengembalikan angka lebih kecil dari 0, kesalahan terjadi. Bagaimana cara mengetahui parameter mana yang tidak divalidasi?
Saya ingat dari hari C saya banyak fungsi mengembalikan kode kesalahan seperti ini:
dll.
Apakah ini benar-benar kurang mudah dibaca daripada melempar dan menangkap pengecualian?
sumber
Anda dapat menggunakan cakar palu untuk memutar sekrup, sama seperti Anda dapat menggunakan pengecualian untuk aliran kontrol. Itu tidak berarti itu adalah penggunaan fitur yang dimaksudkan. The
if
mengekspresikan pernyataan kondisi, yang dimaksudkan penggunaan yang mengendalikan aliran.Jika Anda menggunakan fitur dengan cara yang tidak disengaja saat memilih untuk tidak menggunakan fitur yang dirancang untuk tujuan itu, akan ada biaya yang terkait. Dalam hal ini, kejelasan dan kinerja menderita tanpa nilai tambah nyata. Apa yang menggunakan pengecualian membeli Anda dari
if
pernyataan yang diterima secara luas ?Mengatakan dengan cara lain: hanya karena Anda tidak dapat berarti Anda harus melakukannya .
sumber
if
untuk penggunaan normal atau penggunaan eksekusi tidak dimaksudkan karena tidak dimaksudkan (argumen melingkar)?public class ExitHelper{ public static void cleanExit() { cleanup(); System.exit(1); } }
Lalu panggil saja itu alih-alih melempar:ExitHelper.cleanExit();
Jika argumen Anda masuk akal, maka ini akan menjadi pendekatan yang disukai dan tidak akan ada pengecualian. Anda pada dasarnya mengatakan, "Satu-satunya alasan pengecualian adalah jatuh dengan cara yang berbeda."if
.Seperti yang disebutkan orang lain secara berulang-ulang, prinsip ketakjuban akan melarang Anda menggunakan pengecualian secara berlebihan untuk tujuan kontrol aliran saja. Di sisi lain, tidak ada aturan yang 100% benar, dan selalu ada kasus-kasus di mana pengecualian adalah "alat yang tepat" - sama seperti
goto
itu sendiri, omong-omong, yang dikirimkan dalam bentukbreak
dancontinue
dalam bahasa seperti Jawa, yang sering kali merupakan cara sempurna untuk melompat keluar dari lilitan bersarang, yang tidak selalu dapat dihindari.Posting blog berikut menjelaskan kasus penggunaan yang agak rumit tetapi juga menarik untuk non-lokal
ControlFlowException
:Ini menjelaskan bagaimana di dalam jOOQ (pustaka abstraksi SQL untuk Java) , pengecualian seperti itu kadang-kadang digunakan untuk membatalkan proses rendering SQL lebih awal ketika beberapa kondisi "langka" terpenuhi.
Contoh dari kondisi tersebut adalah:
Nilai ikatan terlalu banyak ditemui. Beberapa basis data tidak mendukung angka bind nilai sembarang dalam pernyataan SQL mereka (SQLite: 999, Ingres 10.1.0: 1024, Sybase ASE 15.5: 2000, SQL Server 2008: 2100). Dalam kasus-kasus tersebut, JOOQ membatalkan fase rendering SQL dan merender kembali pernyataan SQL dengan nilai-nilai binding yang digarisbawahi. Contoh:
Jika kami secara eksplisit mengekstraksi nilai ikat dari kueri AST untuk menghitungnya setiap waktu, kami akan membuang siklus CPU yang berharga untuk 99,9% kueri yang tidak mengalami masalah ini.
Beberapa logika hanya tersedia secara tidak langsung melalui API yang kami ingin jalankan hanya "sebagian". The
UpdatableRecord.store()
metode menghasilkanINSERT
atauUPDATE
pernyataan, tergantung padaRecord
bendera internal. Dari "luar", kita tidak tahu jenis logika apa yang terkandungstore()
(misalnya penguncian optimistis, penanganan pendengar acara, dll.) Sehingga kami tidak ingin mengulangi logika itu ketika kami menyimpan beberapa catatan dalam pernyataan kumpulan, di mana kami inginstore()
hanya menghasilkan pernyataan SQL, tidak benar-benar menjalankannya. Contoh:Jika kami telah meng-eksternal-kan
store()
logikanya ke dalam API "yang dapat digunakan kembali" yang dapat dikustomisasi untuk tidak mengeksekusi SQL, kami akan mencari cara membuat API yang agak sulit dipertahankan dan sulit digunakan kembali.Kesimpulan
Intinya, penggunaan non-lokal
goto
ini sesuai dengan apa yang dikatakan [Mason Wheeler] [5] dalam jawabannya:Kedua penggunaan
ControlFlowExceptions
agak mudah diimplementasikan dibandingkan dengan alternatif mereka, memungkinkan kami untuk menggunakan kembali berbagai logika tanpa refactoring keluar dari internal yang relevan.Tapi perasaan ini menjadi sedikit kejutan bagi pemelihara masa depan tetap ada. Kode terasa agak halus dan meskipun itu adalah pilihan yang tepat dalam kasus ini, kami selalu memilih untuk tidak menggunakan pengecualian untuk aliran kontrol lokal , di mana mudah untuk menghindari menggunakan percabangan biasa
if - else
.sumber
Biasanya tidak ada yang salah, per se, dengan menangani pengecualian pada level rendah. Pengecualian ADALAH pesan yang valid yang memberikan banyak detail mengapa operasi tidak dapat dilakukan. Dan jika Anda bisa mengatasinya, Anda harus melakukannya.
Secara umum jika Anda tahu ada kemungkinan kegagalan yang tinggi yang dapat Anda periksa ... Anda harus melakukan pemeriksaan ... yaitu if (obj! = Null) obj.method ()
Dalam kasus Anda, saya tidak cukup terbiasa dengan pustaka C # untuk mengetahui apakah waktu tanggal memiliki cara mudah untuk memeriksa apakah cap waktu berada di luar batas. Jika ya, panggil saja if (.isvalid (ts)) jika tidak, kode Anda pada dasarnya baik-baik saja.
Jadi, pada dasarnya turun ke cara mana saja menciptakan kode bersih ... jika operasi untuk menjaga terhadap pengecualian yang diharapkan lebih kompleks daripada hanya menangani pengecualian; daripada Anda memiliki izin saya untuk menangani pengecualian daripada menciptakan penjaga yang kompleks di mana-mana.
sumber
Jika Anda menggunakan penangan pengecualian untuk aliran kontrol, Anda terlalu umum dan malas. Seperti yang disebutkan orang lain, Anda tahu sesuatu terjadi jika Anda menangani pemrosesan di handler, tetapi apa sebenarnya? Pada dasarnya Anda menggunakan pengecualian untuk pernyataan lain, jika Anda menggunakannya untuk aliran kontrol.
Jika Anda tidak tahu keadaan apa yang mungkin terjadi, maka Anda dapat menggunakan penangan pengecualian untuk keadaan tidak terduga, misalnya ketika Anda harus menggunakan perpustakaan pihak ketiga, atau Anda harus menangkap semua yang ada di UI untuk menunjukkan kesalahan yang bagus. pesan dan catat pengecualiannya.
Namun, jika Anda tahu apa yang salah, dan Anda tidak memberikan pernyataan if atau sesuatu untuk memeriksanya, maka Anda hanya malas. Membiarkan handler pengecualian menjadi catch-all untuk hal-hal yang Anda tahu bisa terjadi adalah malas, dan itu akan kembali menghantui Anda nanti, karena Anda akan mencoba untuk memperbaiki situasi di handler pengecualian Anda berdasarkan asumsi yang mungkin salah.
Jika Anda memasukkan logika ke pengendali pengecualian untuk menentukan apa yang sebenarnya terjadi, maka Anda akan sangat bodoh karena tidak memasukkan logika itu ke dalam blok percobaan.
Penangan pengecualian adalah pilihan terakhir, karena ketika Anda kehabisan ide / cara untuk menghentikan sesuatu dari kesalahan, atau hal-hal di luar kemampuan Anda untuk mengendalikan. Seperti, server down dan time out dan Anda tidak dapat mencegah pengecualian itu terlempar.
Akhirnya, semua pemeriksaan dilakukan di muka menunjukkan apa yang Anda ketahui atau harapkan akan terjadi dan membuatnya eksplisit. Kode harus jelas maksudnya. Apa yang ingin Anda baca?
sumber
Anda mungkin tertarik untuk melihat sistem kondisi Common Lisp yang merupakan semacam generalisasi pengecualian yang dilakukan dengan benar. Karena Anda dapat melepas tumpukan atau tidak dengan cara yang terkendali, Anda mendapatkan "restart" juga, yang sangat berguna.
Ini tidak ada hubungannya dengan praktik terbaik dalam bahasa lain, tetapi ini menunjukkan kepada Anda apa yang dapat dilakukan dengan beberapa pemikiran desain dalam (kira-kira) arah yang Anda pikirkan.
Tentu saja masih ada pertimbangan kinerja jika Anda memantul ke atas dan ke bawah tumpukan seperti yo-yo, tetapi itu adalah ide yang jauh lebih umum daripada pendekatan "oh crap, lets bail" yang paling banyak diwujudkan oleh sistem penangkapan catch / throw.
sumber
Saya tidak berpikir ada yang salah dengan menggunakan Pengecualian untuk kontrol aliran. Pengecualian agak mirip dengan kelanjutan dan dalam bahasa yang diketik secara statis, Pengecualian lebih kuat dari kelanjutan, jadi, jika Anda membutuhkan kelanjutan tetapi bahasa Anda tidak memilikinya, Anda dapat menggunakan Pengecualian untuk mengimplementasikannya.
Sebenarnya, jika Anda membutuhkan kelanjutan dan bahasa Anda tidak memilikinya, Anda memilih bahasa yang salah dan Anda harus menggunakan yang berbeda. Tapi kadang-kadang Anda tidak punya pilihan: pemrograman web sisi klien adalah yang contoh utama - tidak hanya ada cara untuk mendapatkan sekitar JavaScript.
Contoh: Microsoft Volta adalah proyek yang memungkinkan penulisan aplikasi web dalam .NET, dan membiarkan kerangka kerja mencari tahu bit mana yang perlu dijalankan di mana. Salah satu konsekuensi dari ini adalah bahwa Volta harus dapat mengkompilasi CIL ke JavaScript, sehingga Anda dapat menjalankan kode pada klien. Namun, ada masalah: .NET memiliki multithreading, JavaScript tidak. Jadi, Volta mengimplementasikan kelanjutan dalam JavaScript menggunakan Pengecualian JavaScript, lalu mengimplementasikan .NET Threads menggunakan kelanjutan tersebut. Dengan begitu, aplikasi Volta yang menggunakan utas dapat dikompilasi untuk dijalankan di peramban yang tidak dimodifikasi - tidak diperlukan Silverlight.
sumber
Salah satu alasan estetika:
Mencoba selalu disertai dengan tangkapan, sedangkan jika tidak harus datang dengan yang lain.
Dengan mencoba / menangkap, itu menjadi jauh lebih bertele-tele.
Itu 6 baris kode terlalu banyak.
sumber
Tetapi Anda tidak akan selalu tahu apa yang terjadi dalam Metode yang Anda panggil. Anda tidak akan tahu persis di mana pengecualian itu dilemparkan. Tanpa memeriksa objek pengecualian secara lebih rinci ....
sumber
Saya merasa tidak ada yang salah dengan teladan Anda. Sebaliknya, adalah dosa untuk mengabaikan pengecualian yang dilemparkan oleh fungsi yang dipanggil.
Dalam JVM, melempar pengecualian tidak terlalu mahal, hanya membuat pengecualian dengan xyzException baru (...), karena yang terakhir melibatkan stack walk. Jadi, jika Anda memiliki beberapa pengecualian yang dibuat sebelumnya, Anda dapat melemparkannya berkali-kali tanpa biaya. Tentu saja, dengan cara ini Anda tidak bisa melewatkan data bersama dengan pengecualian, tapi saya pikir itu adalah hal yang buruk untuk dilakukan.
sumber
Ada beberapa mekanisme umum di mana bahasa dapat memungkinkan metode untuk keluar tanpa mengembalikan nilai dan melepas ke blok "tangkapan" berikutnya:
Mintalah metode memeriksa bingkai tumpukan untuk menentukan situs panggilan, dan menggunakan metadata untuk situs panggilan untuk menemukan informasi tentang
try
blok dalam metode panggilan, atau lokasi di mana metode panggilan menyimpan alamat pemanggilnya; dalam situasi terakhir, periksa metadata untuk penelepon penelepon untuk menentukan dengan cara yang sama dengan penelepon langsung, ulangi sampai orang menemukantry
blok atau tumpukan kosong. Pendekatan ini menambahkan sangat sedikit overhead ke kasus tanpa pengecualian (itu menghalangi beberapa optimasi) tetapi mahal ketika pengecualian terjadi.Mintalah metode mengembalikan bendera "tersembunyi" yang membedakan pengembalian normal dari pengecualian, dan minta penelepon memeriksa bendera dan cabang itu ke rutinitas "pengecualian" jika disetel. Rutin ini menambahkan 1-2 instruksi ke kasus tanpa pengecualian, tetapi relatif sedikit overhead ketika pengecualian terjadi.
Minta penelepon menempatkan informasi atau kode penanganan perkecualian pada alamat tetap relatif terhadap alamat pengembalian yang ditumpuk. Misalnya, dengan ARM, alih-alih menggunakan instruksi "BL subroutine", orang dapat menggunakan urutan:
Untuk keluar secara normal, subrutin hanya akan melakukan
bx lr
ataupop {pc}
; dalam kasus keluar abnormal, subrutin akan mengurangi 4 dari LR sebelum melakukan pengembalian atau penggunaansub lr,#4,pc
(tergantung pada variasi ARM, mode eksekusi, dll.) Pendekatan ini akan rusak sangat buruk jika penelepon tidak dirancang untuk mengakomodasi itu.Bahasa atau kerangka kerja yang menggunakan pengecualian yang dicentang mungkin mendapat manfaat dari memiliki mereka yang ditangani dengan mekanisme seperti # 2 atau # 3 di atas, sementara pengecualian yang tidak dicentang ditangani menggunakan # 1. Meskipun implementasi pengecualian yang diperiksa di Jawa agak mengganggu, mereka tidak akan menjadi konsep yang buruk jika ada sarana yang oleh situs panggilan dapat mengatakan, pada dasarnya, "Metode ini dinyatakan sebagai melempar XX, tapi saya tidak mengharapkannya pernah melakukannya; jika ya, rethrow sebagai pengecualian "tidak dicentang". Dalam kerangka di mana pengecualian diperiksa ditangani dengan cara seperti itu, mereka bisa menjadi cara yang efektif untuk kontrol aliran untuk hal-hal seperti metode parsing yang dalam beberapa konteks mungkin memiliki kemungkinan besar kegagalan, tetapi di mana kegagalan harus mengembalikan informasi yang secara fundamental berbeda dari kesuksesan. Namun saya tidak mengetahui adanya kerangka kerja yang menggunakan pola seperti itu. Sebaliknya, pola yang lebih umum adalah menggunakan pendekatan pertama di atas (biaya minimal untuk kasus tanpa pengecualian, tetapi biaya tinggi ketika pengecualian dilemparkan) untuk semua pengecualian.
sumber