it-swarm-id.com

Kapan harus melempar pengecualian?

Saya memiliki pengecualian yang dibuat untuk setiap kondisi yang tidak diharapkan aplikasi saya. UserNameNotValidException, PasswordNotCorrectException dll.

Namun saya diberitahu bahwa saya tidak boleh membuat pengecualian untuk kondisi tersebut. Dalam UML saya, ADA pengecualian untuk aliran utama, jadi mengapa itu tidak menjadi pengecualian?

Adakah panduan atau praktik terbaik untuk membuat pengecualian?

405
Kwan Cheng

Pedoman pribadi saya adalah: pengecualian dilemparkan ketika asumsi mendasar dari blok kode saat ini ternyata salah.

Contoh 1: katakan saya memiliki fungsi yang seharusnya memeriksa kelas arbitrer dan mengembalikan true jika kelas itu mewarisi dari Daftar <>. Fungsi ini mengajukan pertanyaan, "Apakah objek ini adalah keturunan Daftar?" Fungsi ini seharusnya tidak pernah membuang pengecualian, karena tidak ada area abu-abu dalam operasinya - setiap kelas tunggal baik yang diwariskan atau tidak dari Daftar <>, jadi jawabannya selalu "ya" atau "tidak".

Contoh 2: katakan saya memiliki fungsi lain yang memeriksa Daftar <> dan mengembalikan true jika panjangnya lebih dari 50, dan false jika panjangnya kurang. Fungsi ini menanyakan pertanyaan, "Apakah daftar ini memiliki lebih dari 50 item?" Tetapi pertanyaan ini membuat asumsi - mengasumsikan bahwa objek yang diberikan adalah daftar. Jika saya berikan NULL, maka anggapan itu salah. Dalam hal ini, jika fungsinya kembali antara benar atau salah, maka itu melanggar aturannya sendiri. Fungsi tidak dapat kembali apa pun dan mengklaim bahwa itu menjawab pertanyaan dengan benar. Jadi itu tidak kembali - itu melempar pengecualian.

Ini sebanding dengan "pertanyaan dimuat" fallacy logis. Setiap fungsi mengajukan pertanyaan. Jika input yang diberikan membuat pertanyaan itu salah, maka lontarkan pengecualian. Baris ini lebih sulit untuk menggambar dengan fungsi yang mengembalikan batal, tetapi intinya adalah: jika asumsi fungsi tentang inputnya dilanggar, ia harus membuang pengecualian daripada kembali secara normal.

Sisi lain dari persamaan ini adalah: jika Anda menemukan fungsi Anda sering melempar pengecualian, maka Anda mungkin perlu memperbaiki asumsi mereka.

590

Karena mereka adalah hal-hal yang akan terjadi secara normal. Pengecualian bukanlah mekanisme kontrol aliran. Pengguna sering mendapatkan kata sandi yang salah, ini bukan kasus yang luar biasa. Pengecualian harus menjadi hal yang benar-benar langka, UserHasDiedAtKeyboard ketik situasi.

278
blowdart

Pedoman kecil saya sangat dipengaruhi oleh buku "Kode lengkap":

  • Gunakan pengecualian untuk memberi tahu tentang hal-hal yang tidak boleh diabaikan.
  • Jangan gunakan pengecualian jika kesalahan dapat ditangani secara lokal
  • Pastikan pengecualian berada pada tingkat abstraksi yang sama dengan sisa rutinitas Anda.
  • Pengecualian harus disediakan untuk apa yang benar-benar luar biasa.
61
Commander Keen

Ini BUKAN pengecualian jika nama pengguna tidak valid atau kata sandi tidak benar. Itulah hal-hal yang harus Anda harapkan dalam aliran operasi normal. Pengecualian adalah hal-hal yang bukan bagian dari operasi program normal dan agak jarang.

EDIT: Saya tidak suka menggunakan pengecualian karena Anda tidak bisa tahu apakah metode melempar pengecualian hanya dengan melihat panggilan. Karena itulah pengecualian hanya boleh digunakan jika Anda tidak dapat menangani situasi dengan cara yang layak (pikirkan "kehabisan memori" atau "komputer menyala").

34
EricSchaefer

Satu aturan praktis adalah dengan menggunakan pengecualian dalam hal sesuatu yang biasanya tidak dapat Anda prediksi. Contohnya adalah konektivitas database, file yang hilang pada disk, dll. Untuk skenario yang dapat Anda prediksi, yaitu pengguna yang mencoba masuk dengan kata sandi yang buruk, Anda harus menggunakan fungsi yang mengembalikan boolean dan tahu bagaimana menangani situasi dengan anggun. Anda tidak ingin secara tiba-tiba mengakhiri eksekusi dengan melemparkan pengecualian hanya karena seseorang salah mengetik kata sandi mereka.

25
japollock

Lainnya mengusulkan bahwa pengecualian tidak boleh digunakan karena login yang buruk diharapkan dalam aliran normal jika pengguna salah ketik. Saya tidak setuju dan saya tidak mendapatkan alasan. Bandingkan dengan membuka file .. jika file tidak ada atau tidak tersedia karena suatu alasan maka pengecualian akan dilemparkan oleh kerangka kerja. Menggunakan logika di atas ini adalah kesalahan oleh Microsoft. Mereka seharusnya mengembalikan kode kesalahan. Sama untuk penguraian, permintaan web, dll., Dll.

Saya tidak menganggap bagian login yang buruk dari aliran normal, ini luar biasa. Biasanya pengguna mengetik kata sandi yang benar, dan file itu ada. Kasing luar biasa luar biasa dan sangat baik untuk menggunakan pengecualian untuk itu. Menyulitkan kode Anda dengan menyebarkan nilai kembali melalui level n di atas tumpukan adalah pemborosan energi dan akan menghasilkan kode berantakan. Lakukan hal paling sederhana yang mungkin bisa berhasil. Jangan mengoptimalkan secara prematur dengan menggunakan kode kesalahan, hal-hal luar biasa menurut definisi jarang terjadi, dan pengecualian tidak dikenakan biaya apa pun kecuali Anda membuangnya.

23
Bjorn Reppen

Pengecualian adalah efek yang agak mahal, jika misalnya Anda memiliki pengguna yang memberikan kata sandi tidak valid, biasanya merupakan ide yang lebih baik untuk mengirimkan kembali tanda kegagalan, atau beberapa indikator lain yang tidak valid.

Hal ini disebabkan oleh cara penanganan pengecualian, input buruk yang benar, dan item berhenti penting yang unik harus menjadi pengecualian, tetapi bukan info login yang gagal.

16
Mitchel Sellers

Saya pikir Anda hanya harus melempar pengecualian ketika tidak ada yang dapat Anda lakukan untuk keluar dari kondisi Anda saat ini. Misalnya jika Anda mengalokasikan memori dan tidak ada yang mengalokasikan. Dalam kasus yang Anda sebutkan, Anda dapat dengan jelas pulih dari status tersebut dan dapat mengembalikan kode kesalahan kembali ke pemanggil Anda.


Anda akan melihat banyak saran, termasuk dalam jawaban untuk pertanyaan ini, bahwa Anda harus memberikan pengecualian hanya dalam keadaan "luar biasa". Kelihatannya masuk akal, tetapi saran yang salah, karena itu menggantikan satu pertanyaan ("kapan saya harus melemparkan pengecualian") dengan pertanyaan subyektif lain ("apa yang luar biasa"). Sebagai gantinya, ikuti saran dari Herb Sutter (untuk C++, tersedia di artikel Dr Dobbs Kapan dan Bagaimana Cara Menggunakan Pengecualian , dan juga dalam bukunya dengan Andrei Alexandrescu, C++ Standar Pengkodean ): melempar pengecualian jika, dan hanya jika

  • sebuah prasyarat tidak terpenuhi (yang biasanya membuat salah satu dari yang berikut tidak mungkin) atau
  • alternatif akan gagal memenuhi kondisi pasca atau
  • alternatif akan gagal mempertahankan invarian.

Kenapa ini lebih baik? Bukankah ini menggantikan pertanyaan dengan beberapa pertanyaan tentang prasyarat, postkondisi dan invarian? Ini lebih baik karena beberapa alasan yang terhubung.

  • Prasyarat, postkondisi, dan invarian adalah desain karakteristik program kami (API internalnya), sedangkan keputusan untuk throw adalah detail implementasi. Ini memaksa kita untuk mengingat bahwa kita harus mempertimbangkan desain dan implementasinya secara terpisah, dan tugas kita saat mengimplementasikan metode adalah menghasilkan sesuatu yang memenuhi batasan desain.
  • Ini memaksa kita untuk berpikir dalam hal prasyarat, postkondisi, dan invarian, yang merupakan asumsi saja yang harus dibuat oleh penelepon metode kita, dan diungkapkan dengan tepat, memungkinkan kopling longgar antara komponen program kami.
  • Kopling longgar itu kemudian memungkinkan kita untuk memperbaiki implementasi, jika perlu.
  • Post-condition dan invarian dapat diuji; itu menghasilkan kode yang dapat dengan mudah diuji unit, karena post-kondisi adalah predikat kode unit-test kami dapat memeriksa (menegaskan).
  • Berpikir dalam hal kondisi pasca secara alami menghasilkan desain yang sukses sebagai kondisi pasca , yang merupakan gaya alami untuk menggunakan pengecualian. Jalur eksekusi normal ("bahagia") program Anda ditata secara linier, dengan semua kode penanganan kesalahan dipindahkan ke klausa catch.
14
Jon

Saya akan mengatakan tidak ada aturan yang keras dan cepat tentang kapan harus menggunakan pengecualian. Namun ada alasan bagus untuk menggunakan atau tidak menggunakannya:

Alasan untuk menggunakan pengecualian:

  • Alur kode untuk kasus umum lebih jelas
  • Dapat mengembalikan informasi kesalahan kompleks sebagai objek (meskipun ini juga dapat dicapai menggunakan parameter "keluar" kesalahan yang dilewatkan oleh referensi)
  • Bahasa umumnya menyediakan beberapa fasilitas untuk mengelola pembersihan rapi jika terjadi pengecualian (coba/akhirnya di Jawa, gunakan dalam C #, RAII dalam C++)
  • Jika tidak ada pengecualian yang dilemparkan, eksekusi dapat kadang-kadang lebih cepat daripada memeriksa kode pengembalian
  • Di Jawa, pengecualian yang dicek harus dinyatakan atau ditangkap (meskipun ini bisa menjadi alasan untuk menentang)

Alasan untuk tidak menggunakan pengecualian:

  • Kadang-kadang berlebihan jika penanganan kesalahannya sederhana
  • Jika pengecualian tidak didokumentasikan atau dideklarasikan, mereka mungkin tidak tertangkap oleh kode panggilan, yang mungkin lebih buruk daripada jika kode panggilan hanya mengabaikan kode kembali (keluar aplikasi vs kegagalan diam - yang lebih buruk mungkin tergantung pada skenario)
  • Dalam C++, kode yang menggunakan pengecualian harus pengecualian aman (bahkan jika Anda tidak melempar atau menangkapnya, tetapi memanggil fungsi melempar secara tidak langsung)
  • Dalam C++, sulit untuk mengetahui kapan suatu fungsi mungkin melempar, oleh karena itu Anda harus paranoid tentang keamanan pengecualian jika Anda menggunakannya
  • Pengecualian melempar dan menangkap pada umumnya jauh lebih mahal dibandingkan dengan memeriksa bendera pengembalian

Secara umum, saya akan lebih cenderung menggunakan pengecualian dalam Java daripada di C++ atau C #, karena saya berpendapat bahwa pengecualian, yang dinyatakan atau tidak, pada dasarnya merupakan bagian dari antarmuka formal suatu fungsi, karena mengubah jaminan pengecualian Anda dapat merusak kode panggilan. Keuntungan terbesar menggunakannya dalam Java IMO, adalah Anda tahu bahwa penelepon Anda HARUS menangani pengecualian, dan ini meningkatkan kemungkinan perilaku yang benar.

Karena itu, dalam bahasa apa pun, saya akan selalu mendapatkan semua pengecualian dalam lapisan kode atau API dari kelas umum, sehingga kode panggilan selalu dapat menjamin untuk menangkap semua pengecualian. Juga saya akan menganggap buruk untuk melempar kelas pengecualian yang khusus untuk implementasi, saat menulis API atau pustaka (mis. Bungkus pengecualian dari lapisan bawah sehingga pengecualian yang diterima oleh pemanggil Anda dapat dipahami dalam konteks antarmuka Anda).

Perhatikan bahwa Java membuat perbedaan antara pengecualian umum dan Runtime karena yang terakhir tidak perlu dideklarasikan. Saya hanya akan menggunakan kelas pengecualian Runtime ketika Anda tahu bahwa kesalahan adalah hasil dari bug dalam program.

10
Robert

Kelas pengecualian seperti kelas "normal". Anda membuat kelas baru ketika "adalah" jenis objek yang berbeda, dengan bidang yang berbeda dan operasi yang berbeda.

Sebagai aturan praktis, Anda harus mencoba menyeimbangkan antara jumlah pengecualian dan rincian dari pengecualian tersebut. Jika metode Anda melempar lebih dari 4-5 pengecualian yang berbeda, Anda mungkin dapat menggabungkan beberapa dari mereka menjadi pengecualian yang lebih "umum", (mis. Dalam kasus "AuthenticationFailedException"), dan menggunakan pesan pengecualian untuk merinci apa yang salah. Kecuali jika kode Anda menangani masing-masing secara berbeda, Anda tidak perlu membuat banyak kelas pengecualian. Dan jika ya, mungkin Anda harus mengembalikan enum dengan kesalahan yang terjadi. Ini sedikit lebih bersih dengan cara ini.

5
Shachar

Jika kode itu berjalan di dalam loop yang kemungkinan akan menyebabkan pengecualian berulang-ulang, maka melempar pengecualian bukanlah hal yang baik, karena mereka cukup lambat untuk N. besar. Tapi tidak ada yang salah dengan melempar pengecualian kustom jika kinerjanya tidak sebuah isu. Pastikan Anda memiliki pengecualian basis yang semuanya mewarisi, yang disebut BaseException atau sesuatu seperti itu. BaseException mewarisi System.Exception, tetapi semua pengecualian Anda mewarisi BaseException. Anda bahkan dapat memiliki jenis pohon Pengecualian untuk mengelompokkan jenis yang serupa, tetapi ini mungkin atau mungkin tidak berlebihan.

Jadi, jawaban singkatnya adalah jika itu tidak menyebabkan penalti kinerja yang signifikan (yang seharusnya tidak kecuali Anda melemparkan banyak pengecualian), maka silakan.

5
Charles Graham

Saya setuju dengan cara japollock di atas sana - melempar pengakuan ketika Anda tidak yakin tentang hasil operasi. Panggilan ke API, mengakses sistem file, panggilan basis data, dll. Setiap kali Anda melewati "batas" bahasa pemrograman Anda.

Saya ingin menambahkan, jangan ragu untuk melempar pengecualian standar. Kecuali jika Anda akan melakukan sesuatu yang "berbeda" (abaikan, email, log, tunjukkan bahwa gambar paus Twitter itu penting, dll.), Maka jangan repot-repot dengan pengecualian khusus.

3
dclaysmith

aturan praktis untuk melempar pengecualian cukup sederhana. Anda melakukannya ketika kode Anda telah memasuki keadaan INVALID yang tidak dapat dibatalkan. jika data dikompromikan atau Anda tidak dapat memutar kembali pemrosesan yang terjadi hingga titik tersebut maka Anda harus menghentikannya. memang apa lagi yang bisa kamu lakukan? logika pemrosesan Anda akhirnya akan gagal di tempat lain. jika Anda dapat memulihkan entah bagaimana kemudian lakukan itu dan jangan membuang pengecualian.

dalam kasus khusus Anda jika Anda dipaksa untuk melakukan sesuatu yang konyol seperti menerima penarikan uang dan hanya kemudian memeriksa pengguna/pasword Anda harus mengakhiri proses dengan melemparkan pengecualian untuk memberitahukan bahwa sesuatu yang buruk telah terjadi dan mencegah kerusakan lebih lanjut.

3
goran

Saya akan mengatakan bahwa umumnya setiap fundamentalisme mengarah ke neraka.

Anda tentu tidak ingin berakhir dengan aliran yang didorong oleh pengecualian, tetapi menghindari pengecualian juga merupakan ide yang buruk. Anda harus menemukan keseimbangan antara kedua pendekatan. Apa yang tidak akan saya lakukan adalah membuat tipe pengecualian untuk setiap situasi luar biasa. Itu tidak produktif.

Yang umumnya saya sukai adalah membuat dua tipe dasar pengecualian yang digunakan di seluruh sistem: LogicalException dan TechnicalException. Ini lebih jauh dapat dibedakan dengan subtipe jika diperlukan, tetapi pada umumnya tidak diperlukan.

Pengecualian teknis menunjukkan pengecualian yang benar-benar tidak terduga seperti server database sedang down, koneksi ke layanan web melempar IOException dan sebagainya.

Di sisi lain pengecualian logis digunakan untuk menyebarkan situasi salah yang kurang parah ke lapisan atas (umumnya beberapa hasil validasi).

Harap dicatat bahwa bahkan pengecualian logis tidak dimaksudkan untuk digunakan secara teratur untuk mengontrol aliran program, tetapi lebih untuk menyoroti situasi ketika aliran harus benar-benar berakhir. Ketika digunakan di Jawa, kedua jenis pengecualian adalah RuntimeException subclass dan penanganan kesalahan sangat berorientasi pada aspek.

Jadi dalam contoh login, mungkin bijaksana untuk membuat sesuatu seperti AuthenticationException dan membedakan situasi konkret dengan nilai enum seperti sernameNotExisting, PasswordMismatch dll. Maka Anda tidak akan berakhir di memiliki hierarki pengecualian yang sangat besar dan dapat menjaga catch block pada level yang dapat dipertahankan. Anda juga dapat dengan mudah menggunakan beberapa mekanisme penanganan pengecualian umum karena Anda memiliki pengecualian yang dikategorikan dan tahu dengan baik apa yang harus disebarkan ke pengguna dan bagaimana caranya.

Penggunaan khas kami adalah untuk membuang LogicalException selama panggilan Layanan Web ketika input pengguna tidak valid. Pengecualian akan dilakukan ke detail SOAPFault dan kemudian dihapus lagi untuk pengecualian pada klien yang mengakibatkan menunjukkan kesalahan validasi pada satu bidang input halaman web tertentu karena pengecualian memiliki pemetaan yang tepat untuk bidang tersebut.

Ini tentu saja bukan satu-satunya situasi: Anda tidak perlu menekan layanan web untuk membuang pengecualian. Anda bebas untuk melakukannya dalam situasi luar biasa (seperti dalam kasus Anda harus gagal-cepat) - itu semua atas kebijakan Anda.

2
Petr Macek

Pengecualian dimaksudkan untuk peristiwa yang merupakan perilaku abnormal, kesalahan, kegagalan, dan semacamnya. Perilaku fungsional, kesalahan pengguna, dll., Harus ditangani oleh logika program. Karena akun atau kata sandi yang buruk adalah bagian yang diharapkan dari aliran logika dalam rutin masuk, itu harus dapat menangani situasi tersebut tanpa kecuali.

2
Joe Skora

Secara umum Anda ingin melempar pengecualian untuk apa pun yang dapat terjadi di aplikasi Anda yang "Luar Biasa"

Dalam contoh Anda, kedua pengecualian tersebut terlihat seperti Anda memanggilnya melalui validasi kata sandi/nama pengguna. Dalam hal ini dapat dikatakan bahwa tidak benar-benar luar biasa bahwa seseorang akan salah ketik nama pengguna/kata sandi.

Mereka adalah "pengecualian" untuk aliran utama UML Anda tetapi lebih banyak "cabang" dalam pemrosesan.

Jika Anda mencoba mengakses file passwd atau database Anda dan tidak bisa, itu akan menjadi kasus yang luar biasa dan akan menjamin membuang pengecualian.

2
Gord

Pertama, jika pengguna API Anda tidak tertarik dengan kegagalan spesifik dan berbutir halus, maka pengecualian khusus untuk mereka tidak ada nilainya.

Karena sering kali tidak mungkin untuk mengetahui apa yang mungkin berguna bagi pengguna Anda, pendekatan yang lebih baik adalah dengan memiliki pengecualian khusus, tetapi pastikan mereka mewarisi dari kelas umum (mis., Std :: exception atau turunannya dalam C++). Itu memungkinkan klien Anda untuk menangkap pengecualian tertentu jika mereka memilih, atau pengecualian yang lebih umum jika mereka tidak peduli.

2
Jason Etheridge

Saya memiliki masalah filosofis dengan penggunaan pengecualian. Pada dasarnya, Anda mengharapkan skenario tertentu terjadi, tetapi alih-alih menanganinya secara eksplisit, Anda mendorong masalah untuk ditangani "di tempat lain". Dan di mana "tempat lain" itu bisa ditebak siapa pun.

2
Dan

Saya memiliki tiga jenis kondisi yang saya tangkap.

  1. Masukan yang salah atau hilang tidak boleh menjadi pengecualian. Gunakan js sisi klien dan sisi server untuk mendeteksi, mengatur atribut, dan meneruskan kembali ke halaman yang sama dengan pesan.

  2. AppException. Ini biasanya merupakan pengecualian yang Anda deteksi dan lempar dengan kode Anda. Dengan kata lain ini adalah yang Anda harapkan (file tidak ada). Log itu, atur pesannya, dan teruskan kembali ke halaman kesalahan umum. Halaman ini biasanya memiliki sedikit info tentang apa yang terjadi.

  3. Pengecualian yang tak terduga. Ini adalah yang tidak Anda ketahui. Catat dengan detail dan teruskan ke halaman kesalahan umum.

Semoga ini membantu

1
Michael

bagi saya Pengecualian harus dilemparkan ketika aturan teknis atau bisnis yang disyaratkan gagal. misalnya jika entitas mobil dikaitkan dengan susunan 4 ban ... jika satu ban atau lebih adalah nol ... pengecualian harus dipecat "NotEnoughTiresException", karena dapat ditangkap pada tingkat sistem yang berbeda dan memiliki signifikan artinya melalui logging. selain itu jika kita hanya mencoba mengendalikan aliran null dan mencegah instanciation mobil. kita mungkin tidak akan pernah menemukan sumber masalahnya, karena ban seharusnya tidak menjadi nol sejak awal.

1
Genjuro

Jawaban sederhananya adalah, setiap kali operasi tidak mungkin (karena salah satu aplikasi OR karena akan melanggar logika bisnis). Jika suatu metode dipanggil dan tidak mungkin untuk melakukan apa metode itu ditulis untuk dilakukan, buanglah Pengecualian. Contoh yang baik adalah konstruktor selalu melempar ArgumentExceptions jika instance tidak dapat dibuat menggunakan parameter yang disediakan. Contoh lain adalah InvalidOperationException, yang dilemparkan ketika operasi tidak dapat dilakukan karena keadaan anggota lain atau anggota kelas.

Dalam kasus Anda, jika metode seperti Login (nama pengguna, kata sandi) dipanggil, jika nama pengguna tidak valid, memang benar untuk melempar UserNameNotValidException, atau PasswordNotCorrectException jika kata sandi salah. Pengguna tidak dapat masuk menggunakan parameter yang disediakan (mis. Tidak mungkin karena akan melanggar otentikasi), jadi lemparkan Pengecualian. Meskipun saya mungkin memiliki dua Pengecualian Anda mewarisi dari ArgumentException.

Karena itu, jika Anda ingin TIDAK melemparkan Pengecualian karena kegagalan login mungkin sangat umum, salah satu strategi adalah membuat metode yang mengembalikan tipe yang mewakili kegagalan yang berbeda. Ini sebuah contoh:

{ // class
    ...

    public LoginResult Login(string user, string password)
    {
        if (IsInvalidUser(user))
        {
            return new UserInvalidLoginResult(user);
        }
        else if (IsInvalidPassword(user, password))
        {
            return new PasswordInvalidLoginResult(user, password);
        }
        else
        {
            return new SuccessfulLoginResult();
        }
    }

    ...
}

public abstract class LoginResult
{
    public readonly string Message;

    protected LoginResult(string message)
    {
        this.Message = message;
    }
}

public class SuccessfulLoginResult : LoginResult
{
    public SucccessfulLogin(string user)
        : base(string.Format("Login for user '{0}' was successful.", user))
    { }
}

public class UserInvalidLoginResult : LoginResult
{
    public UserInvalidLoginResult(string user)
        : base(string.Format("The username '{0}' is invalid.", user))
    { }
}

public class PasswordInvalidLoginResult : LoginResult
{
    public PasswordInvalidLoginResult(string password, string user)
        : base(string.Format("The password '{0}' for username '{0}' is invalid.", password, user))
    { }
}

Sebagian besar pengembang diajarkan untuk menghindari Pengecualian karena overhead yang disebabkan oleh melempar mereka. Sangat bagus untuk sadar sumber daya, tetapi biasanya tidak mengorbankan desain aplikasi Anda. Mungkin itulah alasan Anda diminta untuk tidak membuang dua Pengecualian Anda. Apakah akan menggunakan Pengecualian atau tidak biasanya bermuara pada seberapa sering Pengecualian akan terjadi. Jika ini adalah hasil yang cukup umum atau cukup diharapkan, inilah saat sebagian besar pengembang akan menghindari Pengecualian dan sebagai gantinya membuat metode lain untuk menunjukkan kegagalan, karena dugaan konsumsi sumber daya.

Berikut adalah contoh menghindari menggunakan Pengecualian dalam skenario seperti yang baru saja dijelaskan, menggunakan pola Coba ():

public class ValidatedLogin
{
    public readonly string User;
    public readonly string Password;

    public ValidatedLogin(string user, string password)
    {
        if (IsInvalidUser(user))
        {
            throw new UserInvalidException(user);
        }
        else if (IsInvalidPassword(user, password))
        {
            throw new PasswordInvalidException(password);
        }

        this.User = user;
        this.Password = password;
    }

    public static bool TryCreate(string user, string password, out ValidatedLogin validatedLogin)
    {
        if (IsInvalidUser(user) || 
            IsInvalidPassword(user, password))
        {
            return false;
        }

        validatedLogin = new ValidatedLogin(user, password);

        return true;
    }
}
1
core

Menurut saya, pertanyaan mendasarnya adalah apakah seseorang akan mengharapkan penelepon ingin melanjutkan aliran program normal jika suatu kondisi terjadi. Jika Anda tidak tahu, ada yang memiliki metode doSomething dan trySomething yang terpisah, di mana mantan mengembalikan kesalahan dan yang terakhir tidak, atau memiliki rutin yang menerima parameter untuk menunjukkan apakah pengecualian harus dilemparkan jika gagal). Pertimbangkan kelas untuk mengirim perintah ke sistem jarak jauh dan melaporkan respons. Perintah tertentu (mis. Restart) akan menyebabkan sistem jarak jauh mengirimkan respons tetapi kemudian tidak responsif untuk jangka waktu tertentu. Karena itu berguna untuk dapat mengirim perintah "ping" dan mencari tahu apakah sistem jarak jauh merespon dalam waktu yang wajar tanpa harus membuang pengecualian jika tidak (penelepon mungkin akan berharap bahwa beberapa yang pertama " upaya "ping akan gagal, tetapi akhirnya akan berhasil). Di sisi lain, jika seseorang memiliki urutan perintah seperti:

 exchange_command ("open tempfile"); 
 exchange_command ("tulis data tempfile {apapun}"); 
 exchange_command ("tulis data tempfile {apapun}"); 
 exchange_command ("tulis data tempfile {apapun}"); 
 exchange_command ("tulis data tempfile {apapun}"); 
 exchange_command ("close tempfile"); 
 exchange_command ("salin tempfile ke realfile"); 

orang ingin kegagalan operasi apa pun untuk membatalkan seluruh urutan. Sementara satu dapat memeriksa setiap operasi untuk memastikan itu berhasil, itu lebih bermanfaat untuk memiliki exchange_command () rutin melempar pengecualian jika perintah gagal.

Sebenarnya, dalam skenario di atas, mungkin bermanfaat untuk memiliki parameter untuk memilih sejumlah mode penanganan kegagalan: jangan pernah melempar pengecualian, melempar pengecualian hanya untuk kesalahan komunikasi, atau melempar pengecualian dalam kasus di mana perintah tidak mengembalikan "keberhasilan" "indikasi.

1
supercat

alasan utama untuk menghindari melempar pengecualian adalah bahwa ada banyak overhead yang terlibat dengan melemparkan pengecualian.

Satu hal yang dinyatakan dalam artikel di bawah ini adalah pengecualian untuk kondisi dan kesalahan luar biasa.

Nama pengguna yang salah tidak selalu merupakan kesalahan program tetapi kesalahan pengguna ...

Berikut ini adalah titik awal yang layak untuk pengecualian dalam .NET: http://msdn.Microsoft.com/en-us/library/ms229030 (VS.80) .aspx

1
Sam

Keamanan digabungkan dengan contoh Anda: Anda seharusnya tidak memberi tahu penyerang bahwa nama pengguna ada, tetapi kata sandi salah. Itu informasi tambahan yang tidak perlu Anda bagikan. Katakan saja "nama pengguna atau kata sandi salah."

1
anon

Pengecualian yang dilemparkan menyebabkan tumpukan melonggarkan, yang memiliki beberapa dampak kinerja (diakui, lingkungan yang dikelola modern telah meningkatkan hal itu). Masih berulang kali melempar dan menangkap pengecualian dalam situasi bersarang akan menjadi ide yang buruk.

Mungkin lebih penting dari itu, pengecualian dimaksudkan untuk kondisi luar biasa. Mereka tidak boleh digunakan untuk aliran kontrol biasa, karena ini akan merusak pembacaan kode Anda.

1
Arno

Beberapa hal berguna untuk dipikirkan ketika memutuskan apakah pengecualian sesuai:

  1. tingkat kode apa yang ingin Anda jalankan setelah kandidat pengecualian terjadi - yaitu, berapa banyak lapisan tumpukan panggilan yang harus dilepas. Anda biasanya ingin menangani pengecualian sedekat mungkin ke tempat itu terjadi. Untuk validasi nama pengguna/kata sandi, Anda biasanya akan menangani kegagalan dalam blok kode yang sama, daripada membiarkan gelembung pengecualian muncul. Jadi pengecualian mungkin tidak tepat. (OTOH, setelah tiga upaya login gagal, aliran kontrol dapat bergeser ke tempat lain, dan pengecualian mungkin sesuai di sini.)

  2. Apakah acara ini sesuatu yang ingin Anda lihat di log kesalahan? Tidak setiap pengecualian ditulis ke log kesalahan, tetapi berguna untuk bertanya apakah entri ini dalam log kesalahan akan berguna - yaitu, Anda akan mencoba melakukan sesuatu tentang hal itu, atau akan menjadi sampah yang Anda abaikan.

0
Mike Kantor

Ada dua kelas utama pengecualian:

1) Pengecualian sistem (mis. Koneksi basis data terputus) atau 2) Pengecualian pengguna. (mis. Validasi input pengguna, 'kata sandi salah')

Saya merasa terbantu untuk membuat Kelas Pengecualian Pengguna saya sendiri dan ketika saya ingin melempar kesalahan pengguna, saya ingin ditangani secara berbeda (yaitu kesalahan sumber daya ditampilkan kepada pengguna) maka yang perlu saya lakukan dalam penangan kesalahan utama saya adalah memeriksa jenis objek :

            If TypeName(ex) = "UserException" Then
               Display(ex.message)
            Else
               DisplayError("An unexpected error has occured, contact your help  desk")                   
               LogError(ex)
            End If
0
Crusty

"PasswordNotCorrectException" bukan contoh yang baik untuk menggunakan pengecualian. Pengguna mendapatkan kata sandi yang salah memang diharapkan, jadi ini bukan pengecualian IMHO. Anda bahkan mungkin pulih darinya, menampilkan pesan kesalahan yang bagus, jadi itu hanya pemeriksaan validitas.

Pengecualian yang tidak ditangani akan menghentikan eksekusi pada akhirnya - ini bagus. Jika Anda mengembalikan kode false, null, atau error, Anda harus berurusan dengan status program sendiri. Jika Anda lupa memeriksa kondisi di suatu tempat, program Anda mungkin terus berjalan dengan data yang salah, dan Anda mungkin mengalami kesulitan mencari tahu apa terjadi dan di mana.

Tentu saja, Anda dapat menyebabkan masalah yang sama dengan pernyataan tangkapan kosong, tetapi setidaknya mengetahui itu lebih mudah dan tidak mengharuskan Anda untuk memahami logikanya.

Jadi sebagai aturan praktis:

Gunakan mereka di mana pun Anda tidak mau atau tidak bisa pulih dari kesalahan.

0
DanMan

Anda dapat menggunakan sedikit pengecualian umum untuk kondisi itu. Untuk mis. ArgumentException dimaksudkan untuk digunakan ketika ada yang salah dengan parameter ke metode (dengan pengecualian ArgumentNullException). Secara umum Anda tidak perlu pengecualian seperti LessThanZeroException, NotPrimeNumberException dll. Pikirkan pengguna metode Anda. Jumlah kondisi yang ingin dia tangani secara spesifik sama dengan jumlah jenis pengecualian yang harus dilempar metode Anda. Dengan cara ini, Anda dapat menentukan seberapa rinci pengecualian yang akan Anda miliki.

Ngomong-ngomong, selalu berusaha menyediakan beberapa cara bagi pengguna perpustakaan Anda untuk menghindari pengecualian. TryParse adalah contoh yang baik, ia ada sehingga Anda tidak harus menggunakan int.Parse dan menangkap pengecualian. Dalam kasus Anda, Anda mungkin ingin memberikan beberapa metode untuk memeriksa apakah nama pengguna valid atau kata sandi benar sehingga pengguna Anda (atau Anda) tidak perlu melakukan banyak penanganan pengecualian. Semoga ini menghasilkan kode yang lebih mudah dibaca dan kinerja yang lebih baik.

0
Serhat Ozgel

Pada akhirnya keputusan turun ke apakah lebih bermanfaat untuk menangani kesalahan tingkat aplikasi seperti ini menggunakan penanganan pengecualian, atau melalui mekanisme linting Anda sendiri seperti mengembalikan kode status. Saya tidak berpikir ada aturan yang sulit dan cepat tentang mana yang lebih baik, tetapi saya akan mempertimbangkan:

  • Siapa yang memanggil kode Anda? Apakah ini semacam API publik atau perpustakaan internal?
  • Bahasa apa yang Anda gunakan? Jika itu Java, misalnya, maka melempar pengecualian (dicentang) akan membebani pemanggil Anda untuk menangani kondisi kesalahan ini dengan cara tertentu, sebagai lawan dari status pengembalian yang bisa diabaikan. Itu bisa baik atau buruk.
  • Bagaimana kondisi kesalahan lain dalam aplikasi yang sama ditangani? Penelepon tidak akan mau berurusan dengan modul yang menangani kesalahan dengan cara istimewa tidak seperti yang lain dalam sistem.
  • Berapa banyak hal yang bisa salah dengan rutinitas yang bersangkutan, dan bagaimana mereka akan ditangani secara berbeda? Pertimbangkan perbedaan antara serangkaian blok tangkap yang menangani kesalahan yang berbeda dan beralih pada kode kesalahan.
  • Apakah Anda memiliki informasi terstruktur tentang kesalahan yang harus Anda kembalikan? Melempar pengecualian memberi Anda tempat yang lebih baik untuk menyimpan informasi ini daripada hanya mengembalikan status.
0
eli