Saya terjebak dalam memutuskan bagaimana menangani pengecualian dalam aplikasi saya.
Banyak jika masalah saya dengan pengecualian berasal dari 1) mengakses data melalui layanan jarak jauh atau 2) deserialisasi objek JSON. Sayangnya saya tidak dapat menjamin keberhasilan untuk salah satu tugas ini (koneksi jaringan terputus, objek JSON rusak yang di luar kendali saya).
Akibatnya, jika saya menemukan pengecualian, saya hanya menangkapnya di dalam fungsi dan mengembalikan FALSE ke pemanggil. Logika saya adalah bahwa semua penelepon benar-benar peduli adalah jika tugas itu berhasil, bukan mengapa itu tidak berhasil.
Berikut beberapa kode contoh (dalam JAWA) dari metode umum)
public boolean doSomething(Object p_somthingToDoOn)
{
boolean result = false;
try{
// if dirty object then clean
doactualStuffOnObject(p_jsonObject);
//assume success (no exception thrown)
result = true;
}
catch(Exception Ex)
{
//don't care about exceptions
Ex.printStackTrace();
}
return result;
}
Saya pikir pendekatan ini baik-baik saja, tetapi saya benar-benar ingin tahu apa praktik terbaik untuk mengelola pengecualian (haruskah saya benar-benar membuat pengecualian sepanjang tumpukan panggilan?).
Ringkasan pertanyaan kunci:
- Bolehkah hanya menangkap pengecualian tetapi tidak melembungkannya atau memberi tahu sistem secara resmi (baik melalui log atau pemberitahuan kepada pengguna)?
- Praktik terbaik apa yang tersedia untuk pengecualian yang tidak mengakibatkan semua yang memerlukan blok coba / tangkap?
Tindak Lanjut / Edit
Terima kasih atas semua umpan baliknya, temukan beberapa sumber bagus tentang manajemen pengecualian online:
- Praktik Terbaik untuk Penanganan Pengecualian | O'Reilly Media
- Pengecualian Penanganan Praktik Terbaik di .NET
- Praktik Terbaik: Manajemen Pengecualian (Artikel sekarang mengarah ke salinan archive.org)
- Antipattern Penanganan Pengecualian
Tampaknya manajemen pengecualian adalah salah satu hal yang bervariasi berdasarkan konteks. Tetapi yang paling penting, seseorang harus konsisten dalam cara mereka mengelola pengecualian dalam suatu sistem.
Selain itu hati-hati terhadap pembusukan kode melalui percobaan / tangkapan yang berlebihan atau tidak memberikan pengecualian rasa hormatnya (pengecualian memperingatkan sistem, apa lagi yang perlu diperingatkan?).
Juga, ini adalah komentar pilihan cantik dari m3rLinEz .
Saya cenderung setuju dengan Anders Hejlsberg dan Anda bahwa sebagian besar penelepon hanya peduli jika operasi berhasil atau tidak.
Dari komentar ini muncul beberapa pertanyaan untuk dipikirkan ketika berhadapan dengan pengecualian:
- Apa gunanya pengecualian ini dilemparkan?
- Bagaimana masuk akal untuk menanganinya?
- Apakah penelepon benar-benar peduli dengan pengecualian atau apakah mereka hanya peduli jika panggilan berhasil?
- Apakah memaksa penelepon untuk mengelola potensi pengecualian itu anggun?
- Apakah Anda menghormati idom bahasa tersebut?
- Apakah Anda benar-benar perlu mengembalikan bendera sukses seperti boolean? Mengembalikan boolean (atau int) lebih merupakan pola pikir C daripada Java (di Java Anda hanya akan menangani pengecualian).
- Ikuti konstruksi manajemen kesalahan yang terkait dengan bahasa :)!
sumber
Jawaban:
Tampaknya aneh bagi saya bahwa Anda ingin menangkap pengecualian dan mengubahnya menjadi kode kesalahan. Menurut Anda mengapa pemanggil lebih memilih kode kesalahan daripada pengecualian ketika yang terakhir adalah default di Java dan C #?
Adapun pertanyaan Anda:
sumber
Ini tergantung pada aplikasi dan situasinya. Jika Anda membuat komponen library, Anda harus menampilkan pengecualian, meskipun pengecualian tersebut harus digabungkan agar kontekstual dengan komponen Anda. Misalnya jika Anda membangun Database Xml dan katakanlah Anda menggunakan sistem file untuk menyimpan data Anda, dan Anda menggunakan izin sistem file untuk mengamankan data. Anda tidak ingin menampilkan pengecualian FileIOAccessDenied karena itu membocorkan implementasi Anda. Sebagai gantinya Anda akan membungkus pengecualian dan melontarkan kesalahan AccessDenied. Ini terutama benar jika Anda mendistribusikan komponen ke pihak ketiga.
Adapun jika tidak apa-apa menelan pengecualian. Itu tergantung pada sistem Anda. Jika aplikasi Anda dapat menangani kasus kegagalan dan tidak ada manfaatnya memberi tahu pengguna mengapa gagal, lanjutkan saja, meskipun saya sangat menyarankan agar Anda mencatat kegagalan. Saya selalu merasa frustasi dipanggil untuk membantu memecahkan masalah dan menemukan mereka menelan pengecualian (atau menggantinya dan melempar yang baru sebagai gantinya tanpa mengatur pengecualian batin).
Secara umum saya menggunakan aturan berikut:
Saya menemukan kode berikut sebagai bau:
Kode seperti ini tidak ada gunanya dan tidak boleh dimasukkan.
sumber
// do something
memasukkantry/finally
blok di sekitar titik yang dilempar,finally
blok akan dieksekusi sebelumcatch
blok. Tanpa itutry/catch
, pengecualian akan terbang ke atas tumpukan tanpa adafinally
blok yang dieksekusi. Ini memungkinkan penangan tingkat atas untuk memutuskan apakah akan mengeksekusifinally
blok atau tidak .Saya ingin merekomendasikan sumber bagus lainnya tentang topik ini. Ini adalah wawancara dengan penemu C # dan Java, masing-masing Anders Hejlsberg dan James Gosling, tentang topik Pengecualian yang Dicentang Java.
Kegagalan dan Pengecualian
Ada juga sumber daya yang bagus di bagian bawah halaman.
Saya cenderung setuju dengan Anders Hejlsberg dan Anda bahwa sebagian besar penelepon hanya peduli jika operasi berhasil atau tidak.
EDIT: Menambahkan detail lebih lanjut tentang percakapan
sumber
FetchData
dan melontarkan pengecualian dari jenis yang tidak diharapkan, ia tidak memiliki cara untuk mengetahui apakah pengecualian itu hanya berarti bahwa data tidak tersedia (dalam hal ini kemampuan kode untuk bertahan tanpanya akan "menyelesaikannya"), atau apakah itu berarti CPU sedang terbakar dan sistem harus melakukan "penghentian keamanan" pada kesempatan pertama. Sepertinya Tn. Hejlsberg menyarankan bahwa kode harus mengasumsikan yang pertama; mungkin itulah strategi terbaik yang diberikan hierarki pengecualian yang ada, tetapi tetap saja tampaknya menjengkelkan.Pengecualian yang dicentang adalah masalah kontroversial pada umumnya, dan di Jawa pada khususnya (nanti saya akan mencoba menemukan beberapa contoh untuk mereka yang mendukung dan menentang mereka).
Sebagai aturan praktis, penanganan pengecualian harus sesuai dengan pedoman ini, tanpa urutan tertentu:
printStackTrace()
atau semacamnya, kemungkinan salah satu pengguna Anda akan mendapatkan salah satu dari pelacakan tumpukan itu pada akhirnya, dan sama sekali tidak memiliki pengetahuan tentang apa yang harus dilakukan dengannya.Exception
, Anda sangat mungkin menelan pengecualian penting.Error
!! , artinya: Jangan pernah menangkapThrowable
s karenaError
s adalah subkelas dari yang terakhir.Error
s adalah masalah yang kemungkinan besar tidak akan pernah bisa Anda tangani (misalnyaOutOfMemory
, atau masalah JVM lainnya)Mengenai kasus spesifik Anda, pastikan bahwa klien apa pun yang memanggil metode Anda akan menerima nilai pengembalian yang sesuai. Jika ada yang gagal, metode pengembalian boolean mungkin menampilkan false, tetapi pastikan tempat Anda memanggil metode tersebut dapat menanganinya.
sumber
Anda seharusnya hanya menangkap pengecualian yang dapat Anda tangani. Misalnya, jika Anda berurusan dengan membaca melalui jaringan dan waktu koneksi habis dan Anda mendapatkan pengecualian, Anda dapat mencoba lagi. Namun jika Anda membaca melalui jaringan dan mendapatkan pengecualian IndexOutOfBounds, Anda benar-benar tidak dapat mengatasinya karena Anda tidak (yah, dalam hal ini Anda tidak akan) tahu apa yang menyebabkannya. Jika Anda akan mengembalikan false atau -1 atau null, pastikan itu untuk pengecualian tertentu. Saya tidak ingin perpustakaan yang saya gunakan mengembalikan false pada jaringan yang dibaca saat pengecualian yang ditampilkan adalah heap kehabisan memori.
sumber
Pengecualian adalah kesalahan yang bukan merupakan bagian dari eksekusi program normal. Bergantung pada apa yang dilakukan program Anda dan kegunaannya (yaitu pengolah kata vs. monitor jantung), Anda akan ingin melakukan hal yang berbeda saat Anda menemukan pengecualian. Saya telah bekerja dengan kode yang menggunakan pengecualian sebagai bagian dari eksekusi normal dan ini jelas merupakan kode bau.
Ex.
Kode ini membuatku muntah. IMO Anda tidak boleh memulihkan dari pengecualian kecuali program kritis. Jika Anda melempar pengecualian maka hal-hal buruk terjadi.
sumber
Semua hal di atas tampaknya masuk akal, dan seringkali tempat kerja Anda mungkin memiliki kebijakan. Di tempat kami, kami telah menetapkan jenis Pengecualian:
SystemException
(tidak dicentang) danApplicationException
(dicentang).Kami telah sepakat bahwa
SystemException
kemungkinan besar tidak dapat dipulihkan dan akan ditangani sekali di atas. Untuk memberikan konteks lebih lanjut, kamiSystemException
s exteneded untuk menunjukkan di mana mereka terjadi, misalnyaRepositoryException
,ServiceEception
, dllApplicationException
s bisa memiliki arti bisnis sepertiInsufficientFundsException
dan harus ditangani oleh kode klien.Tapi sebuah contoh konkret, sulit untuk mengomentari penerapan Anda, tetapi saya tidak akan pernah menggunakan kode pengembalian, ini adalah masalah pemeliharaan. Anda mungkin menelan sebuah Pengecualian, tetapi Anda perlu memutuskan alasannya, dan selalu mencatat peristiwa dan stacktrace. Terakhir, karena metode Anda tidak memiliki pemrosesan lain, metode ini cukup mubazir (kecuali untuk enkapsulasi?), Jadi
doactualStuffOnObject(p_jsonObject);
dapat mengembalikan boolean!sumber
Setelah beberapa pemikiran dan melihat kode Anda, menurut saya Anda hanya melemparkan kembali pengecualian sebagai boolean. Anda bisa membiarkan metode melewati pengecualian ini (Anda bahkan tidak perlu menangkapnya) dan menanganinya di pemanggil, karena di situlah hal itu penting. Jika pengecualian akan menyebabkan pemanggil untuk mencoba kembali fungsi ini, pemanggil haruslah yang menangkap pengecualian.
Kadang-kadang terjadi bahwa pengecualian yang Anda hadapi tidak masuk akal bagi pemanggil (yaitu pengecualian jaringan), dalam hal ini Anda harus menggabungkannya dalam pengecualian khusus domain.
Jika di sisi lain, pengecualian menandakan kesalahan yang tidak dapat diperbaiki dalam program Anda (yaitu hasil akhir dari pengecualian ini adalah penghentian program) Saya pribadi ingin membuatnya eksplisit dengan menangkapnya dan melemparkan pengecualian waktu proses.
sumber
Jika Anda akan menggunakan pola kode dalam contoh Anda, beri nama TryDoSomething, dan tangkap pengecualian tertentu saja.
Pertimbangkan juga untuk menggunakan Filter Pengecualian saat membuat log pengecualian untuk tujuan diagnostik. VB memiliki dukungan bahasa untuk filter Pengecualian. Tautan ke blog Greggm memiliki implementasi yang dapat digunakan dari C #. Filter pengecualian memiliki properti yang lebih baik untuk debuggability atas tangkapan dan lempar ulang. Secara khusus, Anda dapat mencatat masalah di filter dan membiarkan pengecualian terus menyebar. Metode itu memungkinkan pelampiran debugger JIT (Just in Time) untuk memiliki tumpukan asli penuh. Pelemparan ulang memotong tumpukan pada titik lemparan ulang.
Kasus-kasus di mana TryXXXX masuk akal adalah saat Anda menggabungkan fungsi pihak ketiga yang menampilkan kasus yang tidak benar-benar luar biasa, atau yang sederhana sulit untuk diuji tanpa memanggil fungsi tersebut. Contohnya seperti ini:
Apakah Anda menggunakan pola seperti TryXXX atau tidak lebih merupakan pertanyaan gaya. Pertanyaan tentang menangkap semua pengecualian dan menelannya bukanlah masalah gaya. Pastikan pengecualian tak terduga diizinkan untuk disebarkan!
sumber
Saya sarankan mengambil isyarat Anda dari perpustakaan standar untuk bahasa yang Anda gunakan. Saya tidak bisa berbicara untuk C #, tapi mari kita lihat Java.
Misalnya java.lang.reflect.Array memiliki
set
metode statis :Cara C adalah
... dengan nilai pengembalian menjadi indikator keberhasilan. Tapi Anda tidak berada di dunia C lagi.
Setelah Anda menerima pengecualian, Anda akan menemukan bahwa itu membuat kode Anda lebih sederhana dan lebih jelas, dengan memindahkan kode penanganan kesalahan Anda dari logika inti Anda. Bertujuan untuk memiliki banyak pernyataan dalam satu
try
blok.Seperti yang telah dicatat orang lain - Anda harus sespesifik mungkin dalam jenis pengecualian yang Anda tangkap.
sumber
Jika Anda akan menemukan Exception dan mengembalikan false, itu harus menjadi pengecualian yang sangat spesifik. Anda tidak melakukan itu, Anda menangkap semuanya dan kembali salah. Jika saya mendapatkan MyCarIsOnFireException, saya ingin segera mengetahuinya! Pengecualian lainnya yang mungkin tidak saya pedulikan. Jadi Anda harus memiliki setumpuk penangan Exception yang mengatakan "whoa whoa ada sesuatu yang salah di sini" untuk beberapa pengecualian (lempar ulang, atau tangkap dan lempar ulang pengecualian baru yang menjelaskan lebih baik apa yang terjadi) dan hanya mengembalikan false untuk yang lain.
Jika ini adalah produk yang akan Anda luncurkan, Anda harus mencatat pengecualian tersebut di suatu tempat, ini akan membantu Anda menyesuaikannya di masa mendatang.
Sunting: Mengenai pertanyaan membungkus semuanya dalam coba / tangkap, saya pikir jawabannya adalah ya. Pengecualian harus sangat jarang di kode Anda sehingga kode di blok catch dieksekusi sangat jarang sehingga tidak mencapai performa sama sekali. Pengecualian harus berupa keadaan di mana mesin negara Anda rusak dan tidak tahu apa yang harus dilakukan. Setidaknya perlihatkan kembali pengecualian yang menjelaskan apa yang terjadi pada saat itu dan memiliki pengecualian yang tertangkap di dalamnya. "Pengecualian dalam metode doSomeStuff ()" tidak terlalu membantu bagi siapa pun yang harus mencari tahu mengapa perangkat rusak saat Anda sedang berlibur (atau di pekerjaan baru).
sumber
Strategi saya:
Jika fungsi asli mengembalikan batal, saya mengubahnya menjadi bool kembali . Jika terjadi pengecualian / kesalahan, kembalikan false , jika semuanya baik-baik saja, kembalikan true .
Jika fungsi harus mengembalikan sesuatu maka ketika pengecualian / kesalahan terjadi kembalikan null , jika tidak, item yang dapat dikembalikan.
Alih-alih bool sebuah string yang bisa dikembalikan yang berisi deskripsi kesalahan.
Dalam setiap kasus sebelum mengembalikan apapun mencatat kesalahan.
sumber
Beberapa jawaban bagus di sini. Saya ingin menambahkan, bahwa jika Anda akhirnya mendapatkan sesuatu seperti yang Anda posting, setidaknya mencetak lebih dari jejak tumpukan. Katakan apa yang Anda lakukan saat itu, dan Ex. GetMessage (), untuk memberikan kesempatan kepada pengembang.
sumber
blok coba / tangkap membentuk rangkaian logika kedua yang disematkan di set pertama (utama), dengan demikian blok ini merupakan cara yang bagus untuk mengeluarkan kode spaghetti yang tidak terbaca dan sulit untuk di-debug.
Namun, jika digunakan secara wajar, mereka bekerja dengan sangat baik dalam keterbacaan, tetapi Anda sebaiknya mengikuti dua aturan sederhana:
menggunakannya (secara hemat) di tingkat rendah untuk mengetahui masalah penanganan library, dan mengalirkannya kembali ke alur logika utama. Sebagian besar penanganan error yang kita inginkan, harus berasal dari kode itu sendiri, sebagai bagian dari data itu sendiri. Mengapa membuat kondisi khusus, jika data yang dikembalikan tidak istimewa?
gunakan satu penangan besar di tingkat yang lebih tinggi untuk mengelola salah satu atau semua kondisi aneh yang muncul dalam kode yang tidak tertangkap di tingkat rendah. Lakukan sesuatu yang berguna dengan kesalahan (log, restart, pemulihan, dll).
Selain dua jenis penanganan kesalahan ini, semua kode lainnya di tengah harus bebas dan bebas dari kode coba / tangkap dan objek kesalahan. Dengan begitu, ia bekerja dengan sederhana dan seperti yang diharapkan di mana pun Anda menggunakannya, atau apa pun yang Anda lakukan dengannya.
Paul.
sumber
Saya mungkin sedikit terlambat dengan jawabannya tetapi penanganan kesalahan adalah sesuatu yang selalu dapat kami ubah dan berkembang seiring waktu. Jika Anda ingin membaca lebih banyak tentang subjek ini, saya menulis posting di blog baru saya tentang hal itu.http://taoofdevelopment.wordpress.com
Selamat membuat kode.
sumber