Apakah praktik yang baik untuk menangkap pengecualian yang diperiksa dan melempar RuntimeException?

70

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?

RoflcoptrException
sumber
17
"Harga pengecualian yang diperiksa adalah pelanggaran Prinsip Terbuka / Tertutup. Jika Anda melempar pengecualian yang diperiksa dari suatu metode dalam kode Anda dan tangkapannya adalah tiga tingkat di atas, Anda harus menyatakan bahwa pengecualian dalam tanda tangan dari setiap metode antara Anda dan tangkapan Ini berarti bahwa perubahan pada level rendah dari perangkat lunak dapat memaksa perubahan tanda tangan pada banyak level yang lebih tinggi. " —Robert C. Martin, «Kode Bersih», halaman 107
Songo
6
Sangat menarik untuk dicatat bahwa Jim Waldo mengoceh terhadap pengecualian yang tidak diperiksa di "Java: The Good Parts" shop.oreilly.com/product/9780596803742.do mengatakan bahwa programmer dewasa hanya boleh melempar pengecualian yang diperiksa. Kami membacanya di JUG kami hanya 6 tahun yang lalu ketika itu keluar dan sepertinya saran yang bagus! Sekarang, dengan pemrograman fungsional, pengecualian yang diperiksa benar-benar sulit. Bahasa seperti Scala dan Kotlin bahkan tidak memilikinya. Saya sudah mulai membungkus diperiksa dalam pengecualian tidak dicentang juga.
GlenPeterson
@ GlenPeterson Anda juga memiliki saran di FP untuk menghindari eksekusi sekaligus dan gunakan tipe penjumlahan
jk.
Ada juga kasus yang jelas dari antarmuka fungsional: antarmuka fungsional builtin (yaitu 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.
Joel Cornett
Tidak ada yang salah dengan membuat subclass khusus RuntimeException untuk mengkomunikasikan makna melalui pengecualian Anda.
Joel Cornett

Jawaban:

55

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 .

c_maker
sumber
17
Dalam sebagian besar aplikasi kehidupan nyata, ada beberapa kondisi yang tidak dapat dipulihkan. Hampir ada beberapa tingkat di mana Anda dapat dan harus mengatakan "OK, tindakan ini gagal, jadi kami menampilkan / mencatat pesan kesalahan yang bagus dan melanjutkan dengan / menunggu yang berikutnya".
Michael Borgwardt
6
Itu benar, @MichaelBorgwardt, tetapi tempat untuk penanganan semacam itu seringkali berada pada tingkat aplikasi yang paling tinggi, jadi setiap kali saya melihat pengembang "menangani" pengecualian di tingkat yang lebih rendah, biasanya mudah untuk menghapus penanganannya dan hanya meresap pengecualiannya. ke atas. Misalnya, kerangka kerja web seperti JSF menangkap pengecualian di tingkat tertinggi, mencetak pesan log, dan terus memproses permintaan lainnya (tidak mengatakan penanganan default cocok, hanya sebuah contoh).
DavidS
40

Itu bisa BAIK . Silakan baca:

http://onjava.com/pub/a/onjava/2003/11/19/exceptions.html

Sebagian besar waktu, kode klien tidak dapat melakukan apa pun tentang persepsi SQLE. Jangan ragu untuk mengubahnya menjadi pengecualian yang tidak dicentang. Pertimbangkan potongan kode berikut:

public void dataAccessCode(){
  try{
      ..some code that throws SQLException
  }catch(SQLException ex){
      ex.printStacktrace();
  }
} 

Blok tangkapan ini hanya menekan pengecualian dan tidak melakukan apa pun. Pembenarannya adalah bahwa tidak ada yang dapat dilakukan klien saya tentang suatu SQLException. Bagaimana kalau menghadapinya dengan cara berikut?

public void dataAccessCode(){
   try{
       ..some code that throws SQLException
   }catch(SQLException ex){
       throw new RuntimeException(ex);
   }
} 

Ini mengonversi SQLException ke RuntimeException. Jika SQLException terjadi, klausa tangkapan melempar RuntimeException baru. Utas eksekusi ditangguhkan dan pengecualian dilaporkan. Namun, saya tidak merusak lapisan objek bisnis saya dengan penanganan pengecualian yang tidak perlu, terutama karena ia tidak dapat melakukan apa pun tentang SQLException. Jika tangkapan saya membutuhkan akar penyebab pengecualian, saya dapat menggunakan metode getCause () yang tersedia di semua kelas pengecualian pada JDK1.4.

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

Baru-baru ini, beberapa ahli yang dihormati, termasuk Bruce Eckel dan Rod Johnson, secara terbuka menyatakan bahwa sementara mereka awalnya setuju sepenuhnya dengan posisi ortodoks pada pengecualian yang diperiksa, mereka telah menyimpulkan bahwa penggunaan eksklusif pengecualian yang diperiksa bukan ide yang baik seperti itu. muncul pada awalnya, dan pengecualian yang diperiksa telah menjadi sumber masalah yang signifikan bagi banyak proyek besar. Eckel mengambil pandangan yang lebih ekstrem, menunjukkan bahwa semua pengecualian harus tidak dicentang; Pandangan Johnson lebih konservatif, tetapi masih menunjukkan bahwa preferensi ortodoks untuk pengecualian diperiksa adalah berlebihan. (Perlu dicatat bahwa arsitek C #, yang hampir pasti memiliki banyak pengalaman menggunakan teknologi Java, memilih untuk menghilangkan pengecualian yang diperiksa dari desain bahasa, membuat semua pengecualian menjadi pengecualian yang tidak dicentang.

Juga dari tautan yang sama:

Keputusan untuk menggunakan pengecualian yang tidak dicentang adalah keputusan yang rumit, dan jelas bahwa tidak ada jawaban yang jelas. Saran Sun adalah untuk menggunakannya secara gratis, pendekatan C # (yang disetujui Eckel dan lainnya) adalah menggunakannya untuk semuanya. Yang lain mengatakan, "ada jalan tengah."

mrmuggle
sumber
13

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.

Rig
sumber
1
Terima kasih atas petunjuknya. Dan bagaimana jika dia melempar pengecualian khusus yang telah dia implementasikan yang mewarisi langsung dari RuntimeException?
RoflcoptrException
27
@Gary Buyn: banyak orang berpikir bahwa pengecualian yang diperiksa adalah percobaan desain bahasa yang gagal dan mereka adalah orang-orang yang harus digunakan dengan hemat, bukan karena kebiasaan.
Michael Borgwardt
7
@Gary Buyn: Inilah artikel yang menguraikan perdebatan dengan cukup baik: ibm.com/developerworks/java/library/j-jtp05254/index.html Perhatikan juga bahwa lebih dari 15 tahun setelah Jawa memperkenalkan fitur ini, tidak ada bahasa lain yang mengadopsi hal itu, dan C ++ telah menghentikan fitur serupa.
Michael Borgwardt
7
@c_maker: Sebenarnya, Bloch sebagian besar mempromosikan tampilan ortodoks, dan komentar Anda tampaknya terutama tentang menggunakan lebih banyak pengecualian, titik. Pandangan saya adalah bahwa satu-satunya alasan yang sah untuk menggunakan pengecualian yang diperiksa adalah untuk kondisi yang Anda harapkan akan ditangani oleh semua penelepon dengan segera.
Michael Borgwardt
14
Pengecualian pengecoran yang dilemparkan yang tidak perlu melanggar enkapsulasi. Apa yang Anda lakukan, jika metode sederhana seperti 'getAccounts ()' memberi Anda 'SQLException', 'NullPointerException' atau 'FileNotFoundException'? Bisakah kamu mengatasinya? Anda mungkin hanya 'tangkap (Pengecualian e) {}' itu. Selain itu, pengecualian itu - spesifik implementasinya! Seharusnya tidak menjadi bagian dari kontrak! Yang perlu Anda ketahui adalah bahwa ada kesalahan . Dan bagaimana jika implementasinya berubah? Tiba-tiba semuanya harus berubah, menyebabkan metode tidak lagi melempar 'SQLException', tetapi sebuah 'ParseXMLException' sebagai gantinya!
KL
8

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 ...

malejpavouk
sumber
Anda berharap pengembang API tahu apa yang dia lakukan dan menggunakan pengecualian yang dicek dengan baik. Saya mulai melihat API yang mendukung melempar pengecualian runtime sambil juga mendokumentasikannya sehingga klien memiliki opsi untuk menangkapnya jika mau.
c_maker
Metode yang melempar pengecualian umumnya tidak dapat mengetahui apakah penelepon dapat pulih dari itu. Di sisi lain, saya akan menyarankan bahwa metode seharusnya membiarkan pengecualian yang diperiksa dilemparkan oleh metode batin untuk melarikan diri jika tahu mengapa metode dalam melemparkan pengecualian, dan alasannya konsisten dengan metode API luar. Jika metode dalam melempar pengecualian yang diperiksa secara tak terduga, membiarkannya menggelembung sebagai pengecualian yang diperiksa dapat membuat pemanggil salah informasi tentang apa yang terjadi.
supercat
2
Terima kasih telah menyebutkan exception handling layer- mis. Di webapp, filter.
Jake Toronto
5

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.

pengguna606723
sumber
Ini mungkin kasus di dekat bagian atas pohon panggilan, di mana satu-satunya hal yang dapat Anda lakukan adalah mencoba memulihkan dengan anggun dan mengetahui kesalahan spesifik tidak akan membantu. Dalam hal ini, Anda mungkin harus merekam kesalahan dan melanjutkan (memproses catatan berikutnya, memberi tahu pengguna bahwa ada kesalahan, dll). Kalau tidak, tidak. Anda harus selalu menangani pengecualian sedekat kesalahan seperti praktis, tidak membungkusnya sebagai gajah putih untuk penangan berikutnya.
Michael K
@MichaelK Masalahnya adalah "sedekat dengan kesalahan seperti praktis" dalam praktik sering berarti "melalui beberapa lapisan intervensi yang di luar kendali langsung Anda". Misalnya, jika kelas saya harus mengimplementasikan antarmuka tertentu, tangan saya terikat. Itu bisa terjadi secara sewenang-wenang jauh di pohon panggilan. Bahkan ketika antarmuka berada di bawah kendali saya, menambahkan deklarasi lemparan dapat membuat abstraksi bocor jika hanya ada satu set implementasi konkret terbatas yang dapat dibuang. Membuat setiap klien membayar biaya untuk detail implementasi beberapa bukan merupakan tradeoff IMO yang hebat.
Tim Seguine
4

TL; DR

Premis

  • Pengecualian runtime harus dilemparkan ketika kesalahan tidak dapat dipulihkan: ketika kesalahan ada dalam kode, dan tidak tergantung pada keadaan eksternal (dengan demikian, pemulihan akan memperbaiki kode).
  • Pengecualian yang diperiksa harus dilemparkan ketika kode itu benar, tetapi keadaan eksternal tidak seperti yang diharapkan: tidak ada konektivitas jaringan, file tidak ditemukan atau rusak, dll.

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:

float nan = 1/0;

Ini akan membuang pembagian dengan pengecualian runtime nol. Ini sesuai karena kodenya rusak.

Atau misalnya, inilah sebagian HashMapkonstruktor:

public HashMap(int initialCapacity, float loadFactor) {
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity);
    if (initialCapacity > MAXIMUM_CAPACITY)
        initialCapacity = MAXIMUM_CAPACITY;
    if (loadFactor <= 0 || Float.isNaN(loadFactor))
        throw new IllegalArgumentException("Illegal load factor: " +
                loadFactor);
    // more irrelevant code...
}

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:

public void dataAccessCode(){
   try{
       ..some code that throws SQLException
   }catch(SQLException ex){
       throw new RuntimeException(ex);
   }
}

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:

public Data dataAccessCode() throws SQLException {
    // some code that communicates with the database
}

Yang memungkinkan untuk kemungkinan pemulihan oleh penelepon:

public void loadDataAndShowUi() {
    try {
        Data data = dataAccessCode();
        showUiForData(data);
    } catch(SQLException e) {
        // Recover by showing an error alert dialog
        showCantLoadDataErrorDialog();
    }
}

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 dataAccessCodeakan 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:

StringReader sr = new StringReader("{\"test\":\"test\"}");
try {
    doesSomethingWithReader(sr); // calls #read, so propagates IOException
} catch (IOException e) {
    throw new IllegalStateException(e);
}

Dalam contoh ini, kode tersebut menyebar IOExceptionkarena API Readerdirancang untuk mengakses keadaan eksternal, namun kita tahu bahwa StringReaderimplementasi 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 a IOException).


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.

Ben Barkay
sumber
2

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.)

Kasper van den Berg
sumber
2

Ini adalah praktik umum dalam banyak kerangka kerja. Misal Hibernatemelakukan ini dengan tepat. Idenya adalah bahwa API tidak boleh mengganggu untuk sisi klien dan Exceptionmengganggu 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.

pengguna10326
sumber
1

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:

  1. Dari penelepon ke callee, melalui berlalunya argumen.

  2. 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 throwpernyataan) ke penangan (bagian apa pun dari kode Anda mungkin berisi catchblok yang kompatibel dengan pengecualian yang thrown).

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.

ular sanca
sumber
Mungkin baik untuk menyebutkan bahwa masalah semacam ini dapat benar-benar mendatangkan malapetaka dalam kasus di mana metode menjalankan fungsi yang disediakan oleh pemanggilnya. Penulis metode yang menerima fungsi akan dalam banyak kasus tidak memiliki alasan untuk mengetahui atau peduli apa yang diharapkan oleh penelepon, atau pengecualian apa yang mungkin diharapkan oleh penelepon. Jika kode yang menerima metode tidak mengharapkannya untuk membuang pengecualian yang dicentang, metode yang disediakan mungkin harus membungkus pengecualian yang dicentang yang akan dilemparkan ke dalam pengecualian yang tidak diperiksa yang kemudian dapat ditangkap oleh pemasoknya.
supercat
0

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 agedikonversi melalui metode ini, tetapi klien sudah memastikan validasi pada bagiannya, jadi tidak ada gunanya memaksa pemeriksaan pengecualian.

pengguna94369
sumber
0

Sebenarnya ada beberapa pertanyaan di sini

  1. Haruskah Anda mengubah pengecualian yang dicentang menjadi yang tidak dicentang?

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)

  1. Jika Anda akan mengubah pengecualian yang tidak dicentang menjadi pengecualian yang diperiksa, bagaimana Anda harus melakukannya.

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.

Peter Green
sumber
0

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.

GSF
sumber
-2

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.

Tandai xie
sumber
1
Dan apa yang akan Anda lakukan dengan pengecualian di tingkat kerangka kerja?
Matthieu
Jika ada lapisan UI dalam kerangka kerja yang dapat menangani pengecualian, maka UI akan menyajikan pesan kesalahan dari beberapa jenis yang ada yang tidak beres. Dalam hal aplikasi javascript satu halaman, aplikasi dapat menyajikan pesan kesalahan. Memang, lapisan UI harus menangani kesalahan hanya jika lapisan yang lebih dalam benar-benar tidak dapat pulih dari kesalahan.
Jake Toronto