Saya membaca beberapa kode dari seorang kolega dan menemukan bahwa dia sering menangkap berbagai pengecualian dan kemudian selalu melemparkan 'RuntimeException' sebagai gantinya. Saya selalu berpikir ini adalah praktik yang sangat buruk. Apakah aku salah?
java
exceptions
exception-handling
RoflcoptrException
sumber
sumber
Function
,Predicate
, dll) tidak telah parametrized melempar klausa. Ini berarti bahwa Anda perlu menangkap, membungkus, dan me-rethrow setiap pengecualian yang dicentang di loop dalam metode stream () apa pun. Itu dengan sendirinya memberi tahu saya keseimbangan apakah pengecualian yang diperiksa adalah ide yang buruk.Jawaban:
Saya tidak tahu konteks yang cukup untuk mengetahui apakah kolega Anda melakukan sesuatu yang salah atau tidak, jadi saya akan berdebat tentang hal ini secara umum.
Saya tidak berpikir itu selalu merupakan praktik yang salah untuk mengubah pengecualian diperiksa menjadi beberapa rasa pengecualian runtime . Pengecualian diperiksa secara sering disalahgunakan dan disalahgunakan oleh pengembang.
Sangat mudah untuk menggunakan pengecualian yang diperiksa ketika mereka tidak dimaksudkan untuk digunakan (kondisi yang tidak dapat dipulihkan, atau bahkan mengendalikan aliran). Terutama jika pengecualian yang diperiksa digunakan untuk kondisi di mana pemanggil tidak dapat pulih, saya pikir itu dibenarkan untuk mengubah pengecualian itu menjadi pengecualian runtime dengan pesan / keadaan yang membantu. Sayangnya dalam banyak kasus ketika seseorang dihadapkan dengan kondisi yang tidak dapat dipulihkan, mereka cenderung memiliki blok penangkap kosong yang merupakan salah satu hal terburuk yang dapat Anda lakukan. Men-debug masalah seperti itu adalah salah satu kesulitan terbesar yang bisa ditemui pengembang.
Jadi, jika Anda berpikir bahwa Anda berhadapan dengan kondisi yang dapat dipulihkan, kondisi tersebut harus ditangani sesuai dan pengecualian tidak boleh diubah menjadi pengecualian runtime. Jika pengecualian yang diperiksa digunakan untuk kondisi yang tidak dapat dipulihkan, mengubahnya menjadi pengecualian runtime dibenarkan .
sumber
Itu bisa BAIK . Silakan baca:
http://onjava.com/pub/a/onjava/2003/11/19/exceptions.html
Melempar pengecualian yang diperiksa dan tidak dapat pulih darinya tidak membantu.
Beberapa orang bahkan berpikir bahwa pengecualian yang dicentang tidak boleh digunakan sama sekali. Lihat http://www.ibm.com/developerworks/java/library/j-jtp05254/index.html
Juga dari tautan yang sama:
sumber
Tidak, kamu tidak salah. Latihannya sangat salah arah. Anda harus melempar pengecualian yang menangkap masalah yang menyebabkannya. RunTimeException luas dan luas jangkauannya. Itu harus menjadi NullPointerException, ArgumentException, dll. Apa pun yang secara akurat menggambarkan apa yang salah. Ini memberikan kemampuan untuk membedakan masalah yang harus Anda tangani dan membiarkan program bertahan melawan kesalahan yang seharusnya menjadi skenario "Jangan lewati". Apa yang dia lakukan hanya sedikit lebih baik daripada "On Error Resume Next" kecuali ada sesuatu yang hilang dalam info yang disediakan dalam pertanyaan.
sumber
Tergantung.
Praktek ini bahkan mungkin bijaksana . Ada banyak situasi (misalnya dalam pengembangan web), di mana jika beberapa pengecualian terjadi, Anda tidak dapat melakukan apa pun (karena Anda tidak dapat misalnya memperbaiki DB yang tidak konsisten dari kode Anda :-), hanya pengembang yang dapat melakukannya). Dalam situasi ini, sebaiknya bungkus pengecualian yang dilemparkan ke dalam pengecualian runtime sebagai rethrow. Daripada Anda dapat menangkap semua pengecualian ini dalam beberapa lapisan penanganan pengecualian, catat kesalahan tersebut dan tampilkan kepada pengguna beberapa kode + pesan kesalahan lokal yang bagus.
Di sisi lain , jika pengecualian tidak runtime (dicentang), pengembang API menunjukkan, bahwa pengecualian ini dapat diselesaikan dan harus diperbaiki. Jika memungkinkan, maka Anda harus melakukannya.
Solusi lain mungkin untuk memikirkan kembali pengecualian yang diperiksa ini ke dalam lapisan panggilan, tetapi jika Anda tidak dapat menyelesaikannya, di mana pengecualian terjadi, Anda kemungkinan besar tidak akan dapat menyelesaikannya di sini juga ...
sumber
exception handling layer
- mis. Di webapp, filter.Saya ingin mendapat komentar tentang ini, tetapi saya menemukan ada kalanya ini bukan praktik yang buruk. (Atau sangat buruk). Tapi mungkin saya salah.
Seringkali API yang Anda gunakan akan memunculkan pengecualian yang tidak dapat Anda bayangkan benar-benar dilemparkan ke dalam usecase spesifik Anda. Dalam hal ini, tampaknya cukup baik untuk melempar RuntimeException dengan pengecualian yang tertangkap sebagai penyebabnya. Jika pengecualian ini dilempar, kemungkinan akan menjadi penyebab kesalahan pemrograman dan tidak ada dalam batas untuk spesifikasi yang benar.
Dengan asumsi RuntimeException tidak ditangkap dan diabaikan, tidak ada artinya di dekat OnErrorResumeNext.
OnErrorResumeNext akan terjadi ketika seseorang menangkap pengecualian dan hanya mengabaikannya atau hanya mencetaknya. Ini adalah praktik yang sangat buruk di hampir semua kasus.
sumber
TL; DR
Premis
Kesimpulan
Kami dapat mengubah kembali pengecualian yang diperiksa sebagai pengecualian runtime jika kode propagasi atau antarmuka mengasumsikan bahwa implementasi yang mendasarinya bergantung pada keadaan eksternal, padahal jelas tidak.
Bagian ini membahas topik kapan salah satu pengecualian harus dilemparkan. Anda dapat melompat ke bilah horizontal berikutnya jika Anda hanya ingin membaca penjelasan yang lebih rinci untuk kesimpulannya.
Kapan tepat untuk melempar pengecualian runtime? Anda melempar pengecualian runtime ketika jelas bahwa kode tersebut salah, dan pemulihan itu sesuai dengan memodifikasi kode.
Misalnya, layak untuk melemparkan pengecualian runtime untuk yang berikut:
Ini akan membuang pembagian dengan pengecualian runtime nol. Ini sesuai karena kodenya rusak.
Atau misalnya, inilah sebagian
HashMap
konstruktor:Untuk memperbaiki kapasitas awal atau faktor muatan, sebaiknya Anda mengedit kode untuk memastikan bahwa nilai yang benar dilewatkan. Ini tidak tergantung pada beberapa server jauh yang sedang naik, pada kondisi saat ini dari disk, file, atau program lain. Konstruktor yang dipanggil dengan argumen yang tidak valid tergantung pada kebenaran kode panggilan, apakah itu perhitungan yang salah yang menyebabkan parameter tidak valid atau aliran yang tidak pantas yang melewatkan kesalahan.
Kapan tepat untuk melemparkan pengecualian yang diperiksa? Anda melempar pengecualian yang dicentang saat masalah dapat dipulihkan tanpa mengubah kode. Atau dengan kata lain, Anda melemparkan pengecualian yang diperiksa saat kesalahan terkait dengan status sementara kode tersebut benar.
Sekarang kata "pulih" mungkin rumit di sini. Ini bisa berarti bahwa Anda menemukan cara lain untuk mencapai tujuan: Misalnya, jika server tidak merespons maka Anda harus mencoba server berikutnya. Jika pemulihan semacam itu memungkinkan untuk kasus Anda, maka itu hebat, tapi itu bukan satu-satunya cara pemulihan - pemulihan bisa saja menampilkan dialog kesalahan kepada pengguna yang menjelaskan apa yang terjadi, atau jika itu adalah aplikasi server maka itu bisa saja mengirim email ke administrator, atau bahkan sekadar mencatat kesalahan dengan tepat dan singkat.
Mari kita ambil contoh yang disebutkan dalam jawaban mrmuggles:
Ini bukan cara yang benar untuk menangani pengecualian yang diperiksa. Ketidakmampuan belaka untuk menangani pengecualian dalam hal ini lingkup metode ini tidak berarti bahwa aplikasi harus jatuh. Sebagai gantinya, adalah tepat untuk menyebarkannya ke ruang lingkup yang lebih tinggi seperti:
Yang memungkinkan untuk kemungkinan pemulihan oleh penelepon:
Pengecualian yang dicek adalah alat analisis statis, mereka menjelaskan kepada programmer apa yang bisa salah dalam panggilan tertentu tanpa mengharuskan mereka mempelajari implementasinya atau melalui proses coba-coba. Ini membuatnya mudah untuk memastikan bahwa tidak ada bagian dari aliran kesalahan akan diabaikan. Memikirkan kembali pengecualian yang dicentang sebagai pengecualian runtime berfungsi terhadap fitur analisis statis hemat tenaga kerja ini.
Perlu juga disebutkan bahwa lapisan pemanggil memiliki konteks yang lebih baik dari skema yang lebih besar seperti yang telah ditunjukkan di atas. Mungkin ada banyak penyebab yang
dataAccessCode
akan dipanggil, alasan spesifik untuk panggilan tersebut hanya dapat dilihat oleh penelepon - sehingga dapat membuat keputusan yang lebih baik pada pemulihan yang benar atas kegagalan.Sekarang kita sudah memiliki perbedaan ini dengan jelas, kita dapat melanjutkan untuk menyimpulkan ketika ok untuk rethrow pengecualian diperiksa sebagai pengecualian runtime.
Mengingat hal di atas, kapankah pantas untuk melakukan rethrow eksepsi yang dicentang sebagai RuntimeException? Ketika kode yang Anda gunakan mengasumsikan ketergantungan pada keadaan eksternal, tetapi Anda dapat dengan jelas menyatakan bahwa itu tidak tergantung pada keadaan eksternal.
Pertimbangkan yang berikut ini:
Dalam contoh ini, kode tersebut menyebar
IOException
karena APIReader
dirancang untuk mengakses keadaan eksternal, namun kita tahu bahwaStringReader
implementasi tidak mengakses keadaan eksternal. Pada ruang lingkup ini, di mana kita dapat dengan pasti menyatakan bahwa bagian-bagian yang terlibat dalam panggilan tidak mengakses IO atau keadaan eksternal lainnya, kita dapat dengan aman memikirkan kembali pengecualian sebagai pengecualian runtime tanpa kolega yang menakjubkan yang tidak mengetahui implementasi kita (dan mungkin dengan asumsi bahwa kode pengaksesan IO akan membuang aIOException
).Alasan untuk menjaga pengecualian pengecualian keadaan eksternal secara ketat diperiksa adalah bahwa pengecualian itu tidak deterministik (tidak seperti pengecualian yang bergantung pada logika, yang dapat diprediksi akan direproduksi setiap waktu untuk versi kode). Misalnya, jika Anda mencoba untuk membagi dengan 0, Anda akan selalu menghasilkan pengecualian. Jika Anda tidak membagi dengan 0, Anda tidak akan pernah menghasilkan pengecualian, dan Anda tidak harus menangani kasus pengecualian itu, karena itu tidak akan pernah terjadi. Namun, dalam hal mengakses file, berhasil sekali tidak berarti Anda akan berhasil di lain waktu - pengguna mungkin telah mengubah izin, proses lain mungkin telah menghapus atau memodifikasinya. Jadi, Anda selalu harus menangani kasus luar biasa itu, atau Anda mungkin memiliki bug.
sumber
Untuk aplikasi mandiri. Ketika Anda tahu aplikasi Anda tidak dapat menangani pengecualian yang Anda bisa, alih-alih melempar RuntimeException yang dicentang, melempar Kesalahan, membiarkan aplikasi mogok, berharap untuk melaporkan bug, dan memperbaiki aplikasi Anda. (Lihat jawaban dari mrmuggles untuk lebih mendalam diskusi pro dan kontra dari diperiksa vs dicentang.)
sumber
Ini adalah praktik umum dalam banyak kerangka kerja. Misal
Hibernate
melakukan ini dengan tepat. Idenya adalah bahwa API tidak boleh mengganggu untuk sisi klien danException
mengganggu karena Anda harus secara eksplisit menulis kode untuk menangani mereka di tempat di mana Anda memanggil api. Tapi tempat itu mungkin bukan tempat yang tepat untuk menangani pengecualian.Sebenarnya sejujurnya ini adalah topik "panas" dan banyak perselisihan jadi saya tidak akan memihak tetapi saya akan mengatakan bahwa apa yang teman Anda lakukan / usulkan bukanlah tidak biasa atau tidak biasa.
sumber
Keseluruhan "pengecualian yang diperiksa" adalah ide yang buruk.
Pemrograman terstruktur hanya memungkinkan informasi untuk dilewatkan di antara fungsi-fungsi (atau, dalam bahasa Java, metode) ketika mereka "di dekatnya". Lebih tepatnya, informasi hanya dapat bergerak lintas fungsi dengan dua cara:
Dari penelepon ke callee, melalui berlalunya argumen.
Dari callee ke peneleponnya, sebagai mengembalikan nilai.
Ini adalah hal yang pada dasarnya baik. Inilah yang memungkinkan Anda untuk berpikir tentang kode Anda secara lokal: jika Anda perlu memahami atau memodifikasi bagian dari program Anda, Anda hanya perlu melihat bagian itu dan yang "terdekat" lainnya.
Namun, dalam beberapa keadaan, perlu untuk mengirim informasi ke fungsi "jauh", tanpa siapa pun di tengah "tahu". Inilah tepatnya ketika pengecualian harus digunakan. Pengecualian adalah pesan rahasia yang dikirim dari raiser (bagian apa pun dari kode Anda mungkin berisi
throw
pernyataan) ke penangan (bagian apa pun dari kode Anda mungkin berisicatch
blok yang kompatibel dengan pengecualian yangthrow
n).Pengecualian diperiksa menghancurkan kerahasiaan mekanisme, dan, dengan itu, alasan keberadaannya. Jika suatu fungsi mampu membiarkan peneleponnya "mengetahui" informasi, kirimkan saja informasi itu secara langsung sebagai bagian dari nilai pengembalian.
sumber
Ini mungkin tergantung pada kasus per kasus. Dalam skenario tertentu, adalah bijaksana untuk melakukan apa yang teman Anda lakukan, misalnya ketika Anda mengekspos api untuk beberapa klien dan Anda ingin klien menjadi paling tidak menyadari detail implementasi, di mana Anda tahu bahwa pengecualian implementasi tertentu mungkin khusus untuk detail implementasi dan tidak dapat dipaparkan ke klien.
Dengan menjaga pengecualian yang dicentang dari jalan, Anda dapat mengekspos api yang akan memungkinkan klien untuk menulis kode bersih karena klien itu sendiri mungkin pra-memvalidasi kondisi luar biasa.
Misalnya Integer.parseInt (String) mengambil string dan mengembalikan setara integer dan melempar NumberFormatException seandainya string tidak numerik. Sekarang bayangkan pengiriman formulir dengan bidang
age
dikonversi melalui metode ini, tetapi klien sudah memastikan validasi pada bagiannya, jadi tidak ada gunanya memaksa pemeriksaan pengecualian.sumber
Sebenarnya ada beberapa pertanyaan di sini
Aturan umum adalah bahwa pengecualian bahwa penelepon diharapkan untuk menangkap dan memulihkan harus diperiksa. Pengecualian lain (yang mana satu-satunya hasil yang masuk akal adalah untuk membatalkan seluruh operasi atau di mana Anda menganggapnya tidak cukup sehingga khawatir tentang penanganannya secara khusus tidak layak) harus dihapuskan.
Terkadang penilaian Anda tentang apakah pengecualian layak ditangkap dan dipulihkan berbeda dari API yang Anda gunakan. Terkadang konteks penting, pengecualian yang layak ditangani dalam satu situasi mungkin tidak layak ditangani dalam situasi lain. Terkadang tangan Anda dipaksa oleh antarmuka yang ada. Jadi ya ada alasan yang sah untuk mengubah pengecualian yang diperiksa menjadi pengecualian yang tidak dicentang (atau untuk jenis pengecualian yang berbeda)
Pertama dan yang paling penting pastikan Anda menggunakan fasilitas chaining pengecualian. Dengan begitu informasi dari pengecualian asli tidak hilang dan dapat digunakan untuk debugging.
Kedua, Anda harus memutuskan jenis pengecualian apa yang akan digunakan. Menggunakan runtimeexception yang sederhana mempersulit pemanggil untuk menentukan apa yang salah tetapi jika pemanggil mencoba untuk menentukan apa yang salah itu mungkin merupakan indikasi bahwa Anda seharusnya tidak mengubah pengecualian untuk membuatnya tidak dicentang.
sumber
Dalam sebuah pertanyaan boolean, sulit untuk menjawab secara berbeda setelah dua jawaban kontroversial, tetapi saya ingin memberi Anda perspektif yang bahkan disebutkan di beberapa tempat, tidak cukup ditekankan untuk kepentingan yang dimilikinya.
Dengan tahun-tahun saya menemukan bahwa selalu ada orang yang bingung tentang masalah sepele mereka kurang memahami beberapa fundamental.
Layering Aplikasi perangkat lunak (setidaknya seharusnya) setumpuk lapisan satu di atas yang lain. Satu harapan penting untuk pelapisan yang baik adalah bahwa lapisan bawah menyediakan fungsionalitas untuk berpotensi banyak komponen dari lapisan atas.
Katakanlah aplikasi Anda memiliki lapisan berikut dari NET, TCP, HTTP, REST, MODEL DATA, BISNIS dari bawah ke atas.
Jika lapisan bisnis Anda ingin melakukan panggilan istirahat ... tunggu sebentar. Kenapa aku mengatakan itu? Mengapa saya tidak mengatakan permintaan HTTP atau transaksi TCP atau mengirim paket jaringan? Karena itu tidak relevan untuk lapisan bisnis saya. Saya tidak akan menangani mereka, saya tidak akan melihat detailnya. Saya benar-benar baik-baik saja jika mereka jauh di dalam pengecualian yang saya dapatkan sebagai penyebab dan saya tidak ingin tahu bahwa mereka ada.
Terlebih lagi, itu buruk jika saya tahu detail, karena jika besok saya ingin mengubah menggarisbawahi protokol transport berurusan dengan detail yang khusus untuk protokol TCP berarti bahwa abstraksi REST saya tidak melakukan pekerjaan yang baik untuk mengambil sendiri abstrak dari implementasi spesifik.
Ketika mentransisikan pengecualian naik dari lapisan ke lapisan, penting untuk meninjau kembali setiap aspeknya dan apa artinya untuk abstraksi yang disediakan oleh lapisan saat ini. Mungkin untuk mengganti pengecualian dengan yang lain, mungkin menggabungkan beberapa pengecualian. Mungkin juga mentransisikan mereka dari diperiksa ke tidak dicentang atau sebaliknya.
Tentu saja, apakah tempat sebenarnya yang Anda sebutkan itu masuk akal adalah cerita yang berbeda, tetapi secara umum - ya, itu bisa menjadi hal yang baik untuk dilakukan.
sumber
Menurutku,
Pada level framework, kita harus menangkap exception runtime untuk mengurangi lebih banyak blok try catch ke invoker di tempat yang sama.
Di tingkat aplikasi, kami jarang menangkap pengecualian runtime dan saya pikir praktik ini buruk.
sumber