Saya telah membaca saran tentang pertanyaan ini tentang bagaimana pengecualian harus ditangani sedekat mungkin dengan tempat diajukannya.
Dilema saya pada praktik terbaik adalah apakah seseorang harus menggunakan try / catch / akhirnya untuk mengembalikan enum (atau int yang mewakili nilai, 0 untuk kesalahan, 1 untuk ok, 2 untuk peringatan dll, tergantung pada kasus) sehingga jawaban selalu dalam urutan, atau haruskah seseorang membiarkan pengecualian melewati sehingga bagian yang memanggil akan menghadapinya?
Dari apa yang bisa saya kumpulkan, ini mungkin berbeda tergantung pada kasusnya, sehingga saran aslinya tampak aneh.
Misalnya, pada layanan web, Anda selalu ingin mengembalikan keadaan, jadi pengecualian apa pun harus ditangani saat itu juga, tetapi katakanlah di dalam fungsi yang memposting / mendapatkan beberapa data melalui http, Anda ingin pengecualian (misalnya dalam kasus 404) hanya melewati yang memecatnya. Jika tidak, Anda harus membuat beberapa cara untuk menginformasikan bagian panggilan dari kualitas hasil (kesalahan: 404), serta hasilnya sendiri.
Meskipun dimungkinkan untuk mencoba menangkap 404 pengecualian di dalam fungsi helper yang mendapat / memposting data, bukan? Apakah hanya saya yang menggunakan smallint untuk menunjukkan status dalam program (dan mendokumentasikannya dengan tepat tentu saja), dan kemudian menggunakan info ini untuk keperluan validasi kewarasan (semuanya ok / penanganan kesalahan) di luar?
Pembaruan: Saya mengharapkan pengecualian fatal / non-fatal untuk klasifikasi utama, tetapi saya tidak ingin memasukkan ini agar tidak mengurangi jawaban. Izinkan saya mengklarifikasi apa pertanyaannya: Menangani pengecualian yang dilemparkan, bukan melempar pengecualian. Apa efek yang diinginkan: Mendeteksi kesalahan, dan mencoba memulihkannya. Jika pemulihan tidak memungkinkan, berikan umpan balik yang paling berarti.
Sekali lagi, dengan contoh http get / post, pertanyaannya adalah, haruskah Anda memberikan objek baru yang menjelaskan apa yang terjadi pada penelepon asli? Jika pembantu ini ada di perpustakaan yang Anda gunakan, apakah Anda mengharapkannya memberi Anda kode status untuk operasi, atau akankah Anda memasukkannya dalam blok coba-coba? Jika Anda mendesainnya , apakah Anda akan memberikan kode status atau melemparkan pengecualian dan membiarkan tingkat atas menerjemahkannya ke kode status / pesan?
Sinopsis: Bagaimana Anda memilih jika sepotong kode alih-alih menghasilkan pengecualian, mengembalikan kode status bersama dengan hasil apa pun yang dapat dihasilkannya?
sumber
Jawaban:
Pengecualian harus digunakan untuk kondisi luar biasa. Melontarkan pengecualian pada dasarnya membuat pernyataan, "Saya tidak bisa menangani kondisi ini di sini; bisakah seseorang yang lebih tinggi di tumpukan panggilan menangkap ini untuk saya dan menanganinya?"
Mengembalikan nilai bisa lebih baik, jika jelas bahwa pemanggil akan mengambil nilai itu dan melakukan sesuatu yang berarti dengannya. Ini terutama benar jika melempar pengecualian memiliki implikasi kinerja, yaitu dapat terjadi dalam loop yang ketat. Melempar pengecualian membutuhkan waktu lebih lama daripada mengembalikan nilai (dengan setidaknya dua urutan besarnya).
Pengecualian tidak boleh digunakan untuk mengimplementasikan logika program. Dengan kata lain, jangan melemparkan pengecualian untuk menyelesaikan sesuatu; melemparkan pengecualian untuk menyatakan bahwa itu tidak bisa dilakukan.
sumber
Beberapa saran bagus yang pernah saya baca adalah, lempar pengecualian ketika Anda tidak dapat maju mengingat keadaan data yang Anda hadapi, namun jika Anda memiliki metode yang dapat membuang pengecualian, sediakan juga metode yang memungkinkan untuk menegaskan apakah data tersebut benar-benar valid sebelum metode dipanggil.
Sebagai contoh, System.IO.File.OpenRead () akan melempar FileNotFoundException jika file yang diberikan tidak ada, namun ia juga menyediakan metode .Exists () yang mengembalikan nilai boolean yang menunjukkan apakah file tersebut ada yang harus Anda panggil sebelumnya memanggil OpenRead () untuk menghindari pengecualian yang tidak terduga.
Untuk menjawab bagian "kapan saya harus berurusan dengan pengecualian", saya akan mengatakan di mana pun Anda benar-benar dapat melakukan sesuatu tentang hal itu. Jika metode Anda tidak dapat menangani pengecualian yang dilemparkan oleh metode yang dipanggil, jangan tangkap. Biarkan itu meningkatkan rantai panggilan ke sesuatu yang bisa menghadapinya. Dalam beberapa kasus, ini mungkin hanya seorang logger yang mendengarkan Application.UnhandledException.
sumber
Itu desain yang mengerikan. Jangan "menutupi" pengecualian dengan menerjemahkan ke kode numerik. Biarkan itu sebagai pengecualian yang tepat dan tidak ambigu.
Itulah pengecualian untuk.
Bukan kebenaran universal sama sekali. Itu ide yang bagus beberapa kali. Lain kali itu tidak membantu.
sumber
if
pernyataan rumit alih-alih (terkadang) penanganan pengecualian yang lebih sederhana. Jawabannya ("Bagaimana Anda memilih ...") sederhana. Jangan . Saya pikir mengatakan ini menambah percakapan. Namun, Anda bebas untuk mengabaikan jawaban ini.Saya setuju dengan S.Lott . Menangkap pengecualian sedekat mungkin dengan sumbernya mungkin merupakan ide bagus atau ide buruk tergantung pada situasinya. Kunci untuk menangani pengecualian adalah dengan menangkapnya saat Anda dapat melakukan sesuatu. Menangkap mereka dan mengembalikan nilai numerik ke fungsi panggilan pada umumnya adalah desain yang buruk. Anda hanya ingin membiarkannya melayang sampai Anda dapat pulih.
Saya selalu menganggap penanganan pengecualian sebagai langkah menjauh dari logika aplikasi saya. Saya bertanya pada diri sendiri, Jika pengecualian ini dilemparkan seberapa jauh cadangan stack panggilan yang harus saya jelajahi sebelum aplikasi saya dalam keadaan dapat dipulihkan? Dalam banyak kasus, jika tidak ada yang bisa saya lakukan dalam aplikasi untuk memulihkan, itu mungkin berarti saya tidak menangkapnya sampai tingkat atas dan hanya mencatat pengecualian, gagal pekerjaan dan mencoba mematikan dengan bersih.
Sebenarnya tidak ada aturan yang keras dan cepat untuk kapan dan bagaimana mengatur penanganan pengecualian selain membiarkannya sendiri sampai Anda tahu apa yang harus dilakukan dengan mereka.
sumber
Pengecualian adalah hal yang indah. Mereka memungkinkan Anda untuk menghasilkan deskripsi yang jelas tentang masalah run time tanpa menggunakan ambiguitas yang tidak perlu. Pengecualian dapat diketik, diketik-ketik, dan dapat ditangani berdasarkan jenis. Mereka dapat diedarkan untuk penanganan di tempat lain, dan jika mereka tidak dapat ditangani mereka dapat diangkat kembali untuk ditangani pada lapisan yang lebih tinggi dalam aplikasi Anda. Mereka juga akan secara otomatis kembali dari metode Anda tanpa harus menggunakan banyak logika gila untuk berurusan dengan kode kesalahan yang dikaburkan.
Anda harus melempar pengecualian segera setelah menemukan data yang tidak valid dalam kode Anda. Anda harus membungkus panggilan ke metode lain dalam try..catch .. akhirnya untuk menangani pengecualian yang mungkin dilemparkan, dan jika Anda tidak tahu bagaimana menanggapi pengecualian yang diberikan, Anda melemparkannya lagi untuk menunjukkan ke lapisan yang lebih tinggi yang ada sesuatu yang salah yang harus ditangani di tempat lain.
Mengelola kode kesalahan bisa sangat sulit. Anda biasanya berakhir dengan banyak duplikasi yang tidak perlu dalam kode Anda, dan / atau banyak logika berantakan untuk menangani status kesalahan. Menjadi pengguna dan menemukan kode kesalahan bahkan lebih buruk, karena kode itu sendiri tidak akan berarti, dan tidak akan memberikan konteks kepada pengguna untuk kesalahan tersebut. Pengecualian di sisi lain dapat memberi tahu pengguna sesuatu yang bermanfaat, seperti "Anda lupa memasukkan nilai", atau "Anda memasukkan nilai yang tidak valid, berikut ini rentang yang valid yang dapat Anda gunakan ...", atau "Saya tidak tahu apa yang terjadi, hubungi dukungan teknis dan beri tahu mereka bahwa saya baru saja mogok, dan beri mereka jejak tumpukan berikut ... ".
Jadi pertanyaan saya kepada OP adalah mengapa Anda TIDAK ingin menggunakan pengecualian untuk mengembalikan kode kesalahan?
sumber
Semua jawaban bagus. Saya juga ingin menambahkan bahwa mengembalikan kode kesalahan daripada melemparkan pengecualian dapat membuat kode pemanggil lebih rumit. Metode say A memanggil metode B memanggil metode C dan C menemui kesalahan. Jika C mengembalikan kode kesalahan, sekarang B perlu memiliki logika untuk menentukan apakah itu dapat menangani kode kesalahan itu. Jika tidak, maka perlu mengembalikannya ke A. Jika A tidak dapat menangani kesalahan, lalu apa yang Anda lakukan? Melempar pengecualian? Dalam contoh ini, kode jauh lebih bersih jika C hanya melempar pengecualian, B tidak menangkap pengecualian sehingga secara otomatis dibatalkan tanpa kode tambahan yang diperlukan untuk melakukannya dan A dapat menangkap jenis pengecualian tertentu sambil membiarkan orang lain melanjutkan panggilan tumpukan.
Ini mengingatkan aturan yang baik pada kode dengan:
sumber
Saya menggunakan kombinasi kedua solusi: untuk setiap fungsi validasi, saya melewati catatan yang saya isi dengan status validasi (kode kesalahan). Di akhir fungsi, jika ada kesalahan validasi, saya melempar pengecualian, dengan cara ini saya tidak melempar pengecualian untuk setiap bidang, tetapi hanya sekali.
Saya juga mengambil keuntungan bahwa melempar pengecualian akan menghentikan eksekusi karena saya tidak ingin eksekusi berlanjut ketika data tidak valid.
Sebagai contoh
Jika hanya mengandalkan boolean, pengembang yang menggunakan fungsi saya harus mempertimbangkan ini dalam penulisan akun:
tapi dia mungkin lupa dan hanya menelepon
Validate()
(saya tahu dia tidak boleh, tapi mungkin dia mungkin).Jadi, dalam kode di atas saya mendapatkan dua keuntungan:
sumber
Tidak ada satu jawaban di sini - jenis seperti tidak ada satu jenis HttpException.
Sangat masuk akal bahwa pustaka HTTP yang mendasarinya membuat pengecualian ketika mereka mendapatkan respons 4xx atau 5xx; Terakhir kali saya melihat spesifikasi HTTP itu adalah kesalahan.
Adapun melemparkan pengecualian itu - atau membungkusnya dan memikirkan kembali - saya pikir itu benar-benar masalah use case. Misalnya, jika Anda menulis pembungkus untuk mengambil beberapa data dari API dan memaparkannya ke aplikasi, Anda dapat memutuskan bahwa secara semantik permintaan sumber daya yang tidak ada yang mengembalikan HTTP 404 akan lebih masuk akal untuk menangkapnya dan mengembalikan nol. Di sisi lain, kesalahan 406 (tidak dapat diterima) mungkin layak untuk menimbulkan kesalahan karena itu berarti ada sesuatu yang berubah dan aplikasi harusnya mogok dan terbakar dan berteriak minta tolong.
sumber