Saya selalu menemukan diri saya bergulat dengan ini ... mencoba menemukan keseimbangan yang tepat antara mencoba / menangkap dan kode tidak menjadi berantakan tab, kurung, dan pengecualian yang dilemparkan kembali ke tumpukan panggilan seperti kentang panas. Misalnya, saya memiliki aplikasi yang saya kembangkan saat ini yang menggunakan SQLite. Saya memiliki antarmuka Database yang abstrak panggilan SQLite, dan Model yang menerima hal-hal untuk masuk / keluar dari Database ... Jadi jika / ketika pengecualian SQLite terjadi, itu harus dilempar ke Model (yang menyebutnya ), siapa yang harus menyampaikannya kepada siapa pun yang disebut AddRecord / DeleteRecord / apa pun ...
Saya penggemar pengecualian sebagai lawan mengembalikan kode kesalahan karena kode kesalahan dapat diabaikan, dilupakan, dll, sedangkan Pengecualian pada dasarnya harus ditangani (diberikan, saya bisa menangkap dan melanjutkan segera ...) Saya pasti ada cara yang lebih baik daripada apa yang saya lakukan saat ini.
Sunting: Saya seharusnya mengatakan ini sedikit berbeda. Saya mengerti untuk melemparkan ulang sebagai tipe yang berbeda dan semacamnya, saya mengatakannya dengan buruk dan itu adalah kesalahan saya sendiri. Pertanyaan saya adalah ... bagaimana cara terbaik menjaga kode tetap bersih saat melakukannya? Itu hanya mulai terasa sangat berantakan bagi saya setelah beberapa saat.
sumber
Jawaban:
Pikirkan itu dalam hal pengetikan yang kuat, bahkan jika Anda tidak menggunakan bahasa yang sangat diketik - jika metode Anda tidak dapat mengembalikan jenis yang Anda harapkan, itu harus membuang pengecualian.
Selain itu, alih-alih melempar SQLException sepenuhnya ke model (atau lebih buruk, UI), setiap lapisan harus menangkap pengecualian yang diketahui dan membungkus / mengubah / menggantinya dengan pengecualian yang cocok untuk lapisan itu:
Ini akan membantu membatasi jumlah pengecualian yang Anda cari di setiap lapisan dan membantu Anda mempertahankan sistem pengecualian terorganisir.
sumber
throws SQLException
pada metode yang tidak menyiratkan bahwa SQL bahkan terlibat. Dan apa yang terjadi jika Anda memutuskan bahwa beberapa operasi harus pergi ke penyimpanan file? Sekarang Anda harus mendeklarasikanthrows SQLException, IOException
, dll. Itu akan keluar dari tangan.Pengecualian memungkinkan untuk menulis kode pembersih karena sebagian besar menangani kasus normal, dan kasus luar biasa dapat ditangani nanti, bahkan pada konteks yang berbeda.
Aturan untuk menangani perkecualian (penangkapan) adalah harus dilakukan berdasarkan konteks yang benar-benar dapat melakukan sesuatu. Tapi itu memiliki pengecualian:
Pengecualian harus ditangkap pada batas-batas modul (khususnya batas-batas lapisan) dan bahkan jika hanya untuk melampirkan mereka lemparan tingkat yang lebih tinggi yang memiliki arti bagi pemanggil. Setiap modul dan layer harus menyembunyikan detail implementasinya bahkan mengenai pengecualian (modul heap dapat membuang HeapFull tetapi tidak pernah ArrayIndexOutOfBounds).
Dalam contoh Anda, tidak mungkin lapisan atas dapat melakukan apa pun tentang pengecualian SQLite (jika mereka melakukannya, maka itu semua sangat digabungkan ke SQLite sehingga Anda tidak akan dapat mengubah lapisan data ke hal lain). Ada beberapa alasan yang dapat diramalkan untuk hal-hal seperti Tambah / Hapus / Perbarui gagal, dan beberapa di antaranya (perubahan yang tidak kompatibel dalam transaksi bersamaan) tidak mungkin untuk pulih dari bahkan di lapisan data / ketekunan (pelanggaran aturan integritas, fi). Lapisan persistensi harus menerjemahkan pengecualian ke sesuatu yang bermakna dalam istilah lapisan model sehingga lapisan atas dapat memutuskan apakah akan mencoba lagi atau gagal dengan anggun.
sumber
Sebagai aturan umum, Anda hanya harus menangkap Pengecualian spesifik (misalnya IOException), dan hanya jika Anda memiliki sesuatu yang spesifik untuk dilakukan setelah Anda menangkap Pengecualian.
Kalau tidak, sering kali lebih baik untuk membiarkan Pengecualian muncul ke permukaan sehingga mereka dapat diekspos dan ditangani. Beberapa orang menyebutnya gagal-cepat.
Anda harus memiliki semacam pawang di akar aplikasi Anda untuk menangkap Pengecualian yang tidak ditangani yang telah menggelembung dari bawah. Ini memberi Anda kesempatan untuk menyajikan, melaporkan, atau mengelola Pengecualian dengan cara yang sesuai.
Pengecualian Pembungkus berguna ketika Anda perlu melemparkan Pengecualian di sistem terdistribusi dan klien tidak memiliki definisi kesalahan sisi server.
sumber
Bayangkan Anda menulis kelas stack. Anda tidak menempatkan pengecualian dalam menangani kode di kelas, karena itu bisa menghasilkan pengecualian berikut.
Pendekatan sederhana untuk membungkus pengecualian mungkin memutuskan untuk membungkus kedua pengecualian ini dalam kelas pengecualian StackError. Namun, ini benar-benar merindukan titik pembungkus pengecualian. Jika suatu objek melempar pengecualian tingkat rendah, itu berarti objek tersebut rusak. Namun, ada satu kasus di mana ini dapat diterima: ketika objek itu sebenarnya rusak.
Inti dari pembungkus pengecualian adalah bahwa objek harus memberikan pengecualian yang tepat untuk kesalahan normal. Tumpukan harus meningkatkan StackEmpty bukan ArrayIndexError saat muncul dari tumpukan kosong. Tujuannya bukan untuk menghindari melemparkan pengecualian lain jika objek atau kode rusak.
Apa yang kita benar-benar - ingin kita hindari adalah menangkap pengecualian tingkat rendah yang telah melewati objek tingkat tinggi. Kelas stack yang melempar ArrayIndexError ketika muncul dari tumpukan kosong adalah masalah kecil. Jika Anda benar-benar menangkap ArrayIndexError maka kami memiliki masalah serius. Propogasi kesalahan tingkat rendah adalah dosa yang jauh lebih serius daripada menangkapnya.
Untuk membawa ini kembali ke contoh Anda tentang SQLException: mengapa Anda mendapatkan persepsi SQLE? Salah satu alasannya adalah karena Anda melewati kueri yang tidak valid. Namun, jika lapisan akses data Anda menghasilkan kueri buruk, itu rusak. Seharusnya tidak berusaha untuk memperbaiki kerusakannya dalam pengecualian DataAccessFailure.
Namun, SQLException juga bisa muncul karena kehilangan koneksi ke database. Strategi saya pada titik itu adalah untuk menangkap pengecualian di garis pertahanan terakhir, melaporkan kepada pengguna bahwa konektivitas basis data hilang dan ditutup. Karena aplikasi kehilangan akses ke database, sebenarnya tidak banyak yang bisa dilakukan.
Saya tidak tahu seperti apa kode Anda. Tapi sepertinya Anda mungkin menerjemahkan semua pengecualian ke tingkat pengecualian yang lebih tinggi. Anda seharusnya hanya melakukan itu dalam jumlah kasus yang relatif kecil. Sebagian besar pengecualian tingkat yang lebih rendah menunjukkan bug dalam kode Anda. Menangkap dan membungkus mereka kembali adalah kontra-produktif.
sumber