Kapan memilih pengecualian yang dicentang dan tidak dicentang


213

Di Jawa (atau bahasa lain dengan pengecualian yang dicentang), saat membuat kelas pengecualian Anda sendiri, bagaimana Anda memutuskan apakah itu harus diperiksa atau tidak dicentang?

Naluri saya adalah mengatakan bahwa pengecualian yang diperiksa akan dipanggil untuk kasus-kasus di mana penelepon mungkin dapat pulih dengan cara yang produktif, di mana sebagai pengecualian yang tidak diperiksa akan lebih untuk kasus-kasus yang tidak dapat dipulihkan, tetapi saya akan tertarik pada pemikiran orang lain.


11
Barry Ruzek telah menulis panduan yang sangat baik tentang memilih pengecualian yang diperiksa atau tidak dicentang.
sigget

Jawaban:


241

Pengecualian yang diperiksa bagus, asalkan Anda mengerti kapan harus digunakan. API inti Java gagal mengikuti aturan-aturan ini untuk SQLException (dan kadang-kadang untuk IOException) yang mengapa mereka sangat mengerikan.

Pengecualian yang Diperiksa harus digunakan untuk kesalahan yang dapat diprediksi , tetapi tidak dapat dicegah yang masuk akal untuk dipulihkan .

Pengecualian yang tidak dicentang harus digunakan untuk yang lainnya.

Saya akan memecah ini untuk Anda, karena kebanyakan orang salah paham apa artinya ini.

  1. Dapat diprediksi tetapi tidak dapat dicegah : Pemanggil melakukan segala daya mereka untuk memvalidasi parameter input, tetapi beberapa kondisi di luar kendali mereka telah menyebabkan operasi gagal. Misalnya, Anda mencoba membaca file tetapi seseorang menghapusnya di antara waktu Anda memeriksa apakah ada dan saat operasi membaca dimulai. Dengan mendeklarasikan pengecualian yang dicentang, Anda memberi tahu penelepon untuk mengantisipasi kegagalan ini.
  2. Masuk akal untuk pulih dari : Tidak ada gunanya memberitahu penelepon untuk mengantisipasi pengecualian yang tidak dapat mereka pulihkan. Jika pengguna mencoba membaca dari file yang tidak ada, pemanggil dapat meminta mereka untuk nama file baru. Di sisi lain, jika metode gagal karena bug pemrograman (argumen metode tidak valid atau implementasi metode kereta) tidak ada yang dapat dilakukan aplikasi untuk memperbaiki masalah di pertengahan eksekusi. Yang terbaik yang bisa dilakukan adalah mencatat masalah dan menunggu pengembang untuk memperbaikinya di lain waktu.

Kecuali pengecualian yang Anda lempar memenuhi semua kondisi di atas, ia harus menggunakan Pengecualian Tidak Dicentang.

Mengevaluasi ulang di setiap tingkat : Kadang-kadang metode menangkap pengecualian diperiksa bukan tempat yang tepat untuk menangani kesalahan. Dalam hal itu, pertimbangkan apa yang masuk akal untuk penelepon Anda sendiri. Jika pengecualian dapat diprediksi, tidak dapat dicegah, dan masuk akal bagi mereka untuk pulih, Anda harus melemparkan sendiri pengecualian yang dicentang. Jika tidak, Anda harus membungkus pengecualian dalam pengecualian yang tidak dicentang. Jika Anda mengikuti aturan ini, Anda akan menemukan diri Anda mengubah pengecualian yang dicentang ke pengecualian yang tidak dicentang dan sebaliknya tergantung pada lapisan apa Anda berada.

Untuk pengecualian yang dicentang dan tidak dicentang, gunakan level abstraksi yang tepat . Misalnya, repositori kode dengan dua implementasi yang berbeda (database dan sistem file) harus menghindari mengekspos detail spesifik implementasi dengan melempar SQLExceptionatau IOException. Sebagai gantinya, itu harus membungkus pengecualian dalam abstraksi yang mencakup semua implementasi (misalnya RepositoryException).


2
"Anda mencoba membaca file tetapi seseorang menghapusnya di antara waktu Anda memeriksa apakah ada dan saat operasi membaca dimulai." => Bagaimana ini bahkan 'diharapkan'? Bagi saya kedengarannya seperti: Tidak terduga dan dapat dicegah .. Siapa yang mengharapkan file akan dihapus hanya antara 2 pernyataan?
Koray Tugay

9
@ KorayTugay Diharapkan tidak berarti bahwa skenario tersebut tipikal. Itu hanya berarti bahwa kita dapat melihat kesalahan ini terjadi sebelumnya (dibandingkan dengan kesalahan pemrograman yang tidak dapat diprediksi sebelumnya). Unpreventable mengacu pada fakta bahwa tidak ada yang dapat dilakukan oleh programmer untuk mencegah pengguna atau aplikasi lain menghapus file di antara waktu kami memeriksa apakah ada dan saat operasi membaca dimulai.
Gili

Jadi setiap masalah terkait database dalam metode ini harus membuang pengecualian yang diperiksa?
ivanjermakov

59

Dari A Java Learner :

Ketika pengecualian terjadi, Anda harus menangkap dan menangani pengecualian, atau memberi tahu kompiler bahwa Anda tidak dapat menanganinya dengan menyatakan bahwa metode Anda melempar pengecualian itu, maka kode yang menggunakan metode Anda harus menangani pengecualian itu (bahkan juga dapat memilih untuk menyatakan bahwa ia melempar pengecualian jika tidak bisa mengatasinya).

Compiler akan memeriksa bahwa kami telah melakukan salah satu dari dua hal (menangkap, atau menyatakan). Jadi ini disebut Pengecualian. Tetapi Kesalahan, dan Pengecualian Runtime tidak diperiksa oleh kompiler (meskipun Anda dapat memilih untuk menangkap, atau menyatakan, itu tidak diperlukan). Jadi, keduanya disebut pengecualian Tidak Dicentang.

Kesalahan digunakan untuk mewakili kondisi-kondisi yang terjadi di luar aplikasi, seperti crash sistem. Pengecualian runtime biasanya terjadi karena kesalahan dalam logika aplikasi. Anda tidak dapat melakukan apa pun dalam situasi ini. Ketika pengecualian runtime terjadi, Anda harus menulis ulang kode program Anda. Jadi, ini tidak diperiksa oleh kompiler. Pengecualian runtime ini akan terbuka dalam pengembangan, dan periode pengujian. Maka kita harus memperbaiki kode kita untuk menghapus kesalahan ini.


13
Itulah pandangan ortodoks. Tetapi ada banyak kontroversi tentang itu.
artbristol

49

Aturan yang saya gunakan adalah: jangan pernah menggunakan pengecualian yang tidak dicentang! (atau ketika Anda tidak melihat jalan keluar)

Ada kasus yang sangat kuat untuk sebaliknya: Jangan pernah gunakan pengecualian yang diperiksa. Saya enggan untuk memihak dalam debat tetapi tampaknya ada konsensus luas bahwa memperkenalkan pengecualian yang diperiksa adalah keputusan yang salah di belakang. Jangan menembak pembawa pesan dan merujuk kepada mereka argumen .


3
IMHO, pengecualian yang diperiksa bisa menjadi aset utama jika ada cara mudah bagi metode untuk menyatakan bahwa itu tidak mengharapkan metode yang disebut dalam blok kode tertentu untuk melempar pengecualian tertentu (atau apa pun), dan bahwa setiap yang diperiksa pengecualian yang dilontarkan bertentangan dengan ekspektasi tersebut harus dibungkus dengan beberapa tipe pengecualian lain dan di-rethrown. Saya berpendapat bahwa 90% dari waktu ketika kode tidak siap untuk mengatasi pengecualian yang diperiksa, bungkus-dan-rethrow seperti itu akan menjadi cara terbaik untuk menanganinya, tetapi karena tidak ada dukungan bahasa, jarang dilakukan.
supercat

@supercat Pada dasarnya itu saja: Saya penggemar berat jenis ketat memeriksa dan memeriksa pengecualian adalah perpanjangan logis dari itu. Saya telah sepenuhnya mengabaikan pengecualian yang telah diperiksa meskipun secara konsep saya sangat menyukainya.
Konrad Rudolph

1
Satu hal yang saya miliki dengan desain pengecualian, yang mekanisme yang saya jelaskan akan selesaikan, adalah bahwa jika foodidokumentasikan sebagai melempar barExceptionketika membaca melewati akhir file, dan foomemanggil metode yang melempar barExceptionmeskipun footidak mengharapkannya, kode yang memanggil fooakan berpikir bahwa akhir file telah tercapai, dan tidak akan mengetahui bahwa sesuatu yang tidak terduga terjadi. Saya akan menganggap situasi itu sebagai satu-satunya pengecualian yang seharusnya diperiksa paling berguna, tetapi itu juga satu-satunya kasus di mana kompiler akan mengizinkan pengecualian diperiksa tidak tertangani.
supercat

@supercat: Sudah ada cara mudah bagi kode untuk melakukan apa yang Anda inginkan di komentar pertama: bungkus kode dalam blok coba, tangkap Exception, dan bungkus Exception dalam RuntimeException dan rethrow.
Warren Dew

1
@KonradRudolph supercat disebut "blok kode tertentu"; mengingat blok harus didefinisikan, sintaksis deklaratif tidak akan secara signifikan mengurangi mengasapi. Jika Anda berpikir bahwa itu akan menjadi deklaratif untuk seluruh fungsi, itu akan mendorong pemrograman yang buruk karena orang hanya akan menempel pada deklarasi daripada benar-benar melihat pengecualian yang diperiksa berpotensi tertangkap, dan memastikan tidak ada cara lain yang lebih baik untuk menangani mereka.
Warren Dew

46

Pada sistem yang cukup besar, dengan banyak lapisan, pengecualian yang diperiksa tidak berguna karena, bagaimanapun, Anda memerlukan strategi tingkat arsitektur untuk menangani bagaimana pengecualian akan ditangani (gunakan penghalang kesalahan)

Dengan pengecualian yang dicentang, stategy penanganan kesalahan Anda dikelola secara mikro dan tidak tertahankan pada sistem besar apa pun.

Sebagian besar waktu Anda tidak tahu apakah kesalahan "dapat dipulihkan" karena Anda tidak tahu di lapisan apa penelepon API Anda berada.

Katakanlah saya membuat StringToInt API yang mengubah representasi string integer ke Int. Haruskah saya melempar pengecualian yang dicentang jika API disebut dengan string "foo"? Apakah bisa dipulihkan? Saya tidak tahu karena di lapisannya penelepon API StringToInt saya mungkin sudah memvalidasi input, dan jika pengecualian ini dilemparkan, itu adalah bug atau kerusakan data dan tidak dapat dipulihkan untuk lapisan ini.

Dalam hal ini penelepon API tidak ingin menangkap pengecualian. Dia hanya ingin membiarkan pengecualian "menggelembung". Jika saya memilih pengecualian yang dicentang, penelepon ini akan memiliki banyak blok tangkapan tidak berguna hanya untuk secara artifisial mengolah kembali pengecualian.

Apa yang dapat dipulihkan tergantung sebagian besar waktu pada penelepon API, bukan pada penulis API. API tidak boleh menggunakan pengecualian yang dicentang karena hanya pengecualian yang tidak dicentang yang memungkinkan untuk memilih menangkap atau mengabaikan pengecualian.



16
@alexsmail Internet tidak pernah gagal mengejutkan saya, sebenarnya ini adalah blog saya :)
Stephane

30

Kamu benar.

Pengecualian yang tidak dicentang digunakan untuk membiarkan sistem gagal dengan cepat yang merupakan hal yang baik. Anda harus dengan jelas menyatakan apa yang diharapkan metode Anda agar dapat berfungsi dengan baik. Dengan cara ini Anda dapat memvalidasi input hanya sekali.

Misalnya:

/**
 * @params operation - The operation to execute.
 * @throws IllegalArgumentException if the operation is "exit"
 */
 public final void execute( String operation ) {
     if( "exit".equals(operation)){
          throw new IllegalArgumentException("I told you not to...");
     }
     this.operation = operation; 
     .....  
 }
 private void secretCode(){
      // we perform the operation.
      // at this point the opreation was validated already.
      // so we don't worry that operation is "exit"
      .....  
 }

Sekadar memberi contoh. Intinya adalah, jika sistem gagal dengan cepat, maka Anda akan tahu di mana dan mengapa itu gagal. Anda akan mendapatkan stacktrace seperti:

 IllegalArgumentException: I told you not to use "exit" 
 at some.package.AClass.execute(Aclass.java:5)
 at otherPackage.Otherlass.delegateTheWork(OtherClass.java:4569)
 ar ......

Dan Anda akan tahu apa yang terjadi. OtherClass dalam metode "delegateTheWork" (pada baris 4569) memanggil kelas Anda dengan nilai "exit", bahkan ketika seharusnya tidak dilakukan dll.

Kalau tidak, Anda harus memercikkan validasi ke seluruh kode Anda dan itu rawan kesalahan. Plus, kadang-kadang sulit untuk melacak apa yang salah dan Anda mungkin mengharapkan berjam-jam frustasi debugging

Hal yang sama terjadi dengan NullPointerExceptions. Jika Anda memiliki kelas 700 baris dengan sekitar 15 metode, yang menggunakan 30 atribut dan tidak ada yang bisa nol, alih-alih memvalidasi di masing-masing metode untuk nullability, Anda bisa membuat semua atribut itu hanya-baca dan memvalidasi mereka di konstruktor atau metode pabrik.

 public static MyClass createInstane( Object data1, Object data2 /* etc */ ){ 
      if( data1 == null ){ throw NullPointerException( "data1 cannot be null"); }

  }


  // the rest of the methods don't validate data1 anymore.
  public void method1(){ // don't worry, nothing is null 
      ....
  }
  public void method2(){ // don't worry, nothing is null 
      ....
  }
  public void method3(){ // don't worry, nothing is null 
      ....
  }

Pengecualian yang diperiksa Berguna ketika programmer (Anda atau rekan kerja Anda) melakukan segalanya dengan benar, memvalidasi input, menjalankan tes, dan semua kode sempurna, tetapi kode terhubung ke layanan web pihak ketiga yang mungkin turun (atau file) Anda menggunakan telah dihapus oleh proses eksternal lain, dll). Layanan web bahkan dapat divalidasi sebelum koneksi dicoba, tetapi selama transfer data terjadi kesalahan.

Dalam skenario itu tidak ada yang dapat Anda atau rekan kerja Anda lakukan untuk membantunya. Namun tetap saja Anda harus melakukan sesuatu dan tidak membiarkan aplikasi mati dan menghilang begitu saja di mata pengguna. Anda menggunakan pengecualian yang dicentang untuk itu dan menangani pengecualian, apa yang dapat Anda lakukan ketika itu terjadi?, Sebagian besar waktu, hanya untuk mencoba mencatat kesalahan, mungkin menyimpan pekerjaan Anda (aplikasi bekerja) dan menyajikan pesan kepada pengguna . (Situs blabla sedang down, coba lagi nanti dll.)

Jika pengecualian yang dicentang digunakan secara berlebihan (dengan menambahkan "throw Exception" di semua metode tanda tangan), maka kode Anda akan menjadi sangat rapuh, karena semua orang akan mengabaikan pengecualian itu (karena terlalu umum) dan kualitas kode akan menjadi serius dikompromikan.

Jika Anda terlalu sering menggunakan pengecualian yang tidak dicentang, hal serupa akan terjadi. Para pengguna kode itu tidak tahu apakah ada yang salah, banyak yang mencoba {...} catch (Throwable t) akan muncul.


2
Dikatakan dengan baik! +1. Selalu mengejutkan saya penelepon perbedaan ini (tidak dicentang) / callee (dicentang) tidak lebih jelas ...
VonC

19

Inilah 'aturan terakhir saya'.
Saya menggunakan:

  • pengecualian yang tidak dicentang dalam kode metode saya untuk kegagalan karena penelepon (yang melibatkan dokumentasi eksplisit dan lengkap )
  • memeriksa pengecualian untuk kegagalan karena callee yang saya perlu jelaskan kepada siapa pun yang ingin menggunakan kode saya

Dibandingkan dengan jawaban sebelumnya, ini adalah alasan yang jelas (di mana seseorang dapat setuju atau tidak setuju) untuk penggunaan satu atau yang lain (atau keduanya) jenis pengecualian.


Untuk kedua pengecualian tersebut, saya akan membuat Pengecualian saya sendiri yang tidak dicentang dan diperiksa untuk aplikasi saya (praktik yang baik, sebagaimana disebutkan di sini ), kecuali untuk pengecualian yang tidak dicentang yang sangat umum (seperti NullPointerException)

Jadi misalnya, tujuan fungsi khusus di bawah ini adalah untuk membuat (atau mendapatkan jika sudah ada) objek, yang
berarti:

  • wadah objek untuk membuat / mendapatkan HARUS ada (tanggung jawab Penelepon
    => pengecualian tidak dicentang, DAN hapus komentar javadoc untuk fungsi yang disebut ini)
  • parameter lainnya tidak boleh nol
    (pilihan pembuat kode untuk meletakkannya di CALLER: pembuat kode tidak akan memeriksa parameter nol tetapi pembuat kode TIDAK DOKUMEN)
  • hasilnya TIDAK BISA NULL
    (tanggung jawab dan pilihan kode callee, pilihan yang akan sangat menarik bagi penelepon
    => pengecualian yang diperiksa karena setiap penelepon HARUS mengambil keputusan jika objek tidak dapat dibuat / ditemukan, dan bahwa keputusan harus diberlakukan pada waktu kompilasi: mereka tidak dapat menggunakan fungsi ini tanpa harus berurusan dengan kemungkinan ini, artinya dengan pengecualian yang dicentang ini ).

Contoh:


/**
 * Build a folder. <br />
 * Folder located under a Parent Folder (either RootFolder or an existing Folder)
 * @param aFolderName name of folder
 * @param aPVob project vob containing folder (MUST NOT BE NULL)
 * @param aParent parent folder containing folder 
 *        (MUST NOT BE NULL, MUST BE IN THE SAME PVOB than aPvob)
 * @param aComment comment for folder (MUST NOT BE NULL)
 * @return a new folder or an existing one
 * @throws CCException if any problems occurs during folder creation
 * @throws AssertionFailedException if aParent is not in the same PVob
 * @throws NullPointerException if aPVob or aParent or aComment is null
 */
static public Folder makeOrGetFolder(final String aFoldername, final Folder aParent,
    final IPVob aPVob, final Comment aComment) throws CCException {
    Folder aFolderRes = null;
    if (aPVob.equals(aParent.getPVob() == false) { 
       // UNCHECKED EXCEPTION because the caller failed to live up
       // to the documented entry criteria for this function
       Assert.isLegal(false, "parent Folder must be in the same PVob than " + aPVob); }

    final String ctcmd = "mkfolder " + aComment.getCommentOption() + 
        " -in " + getPNameFromRepoObject(aParent) + " " + aPVob.getFullName(aFolderName);

    final Status st = getCleartool().executeCmd(ctcmd);

    if (st.status || StringUtils.strictContains(st.message,"already exists.")) {
        aFolderRes = Folder.getFolder(aFolderName, aPVob);
    }
    else {
        // CHECKED EXCEPTION because the callee failed to respect his contract
        throw new CCException.Error("Unable to make/get folder '" + aFolderName + "'");
    }
    return aFolderRes;
}

19

Ini bukan hanya masalah kemampuan untuk pulih dari pengecualian. Yang paling penting, menurut saya, adalah apakah penelepon tertarik untuk menangkap pengecualian atau tidak.

Jika Anda menulis perpustakaan untuk digunakan di tempat lain, atau lapisan tingkat lebih rendah dalam aplikasi Anda, tanyakan pada diri sendiri apakah pemanggil tertarik untuk menangkap (mengetahui tentang) pengecualian Anda. Jika tidak, gunakan pengecualian yang tidak dicentang, jadi Anda tidak perlu membebani dia.

Ini adalah filosofi yang digunakan oleh banyak kerangka kerja. Pegas dan hibernasi, khususnya, muncul di benak - mereka mengonversi pengecualian yang diketahui diketahui menjadi pengecualian yang tidak dicentang justru karena pengecualian yang dicentang terlalu sering digunakan di Jawa. Salah satu contoh yang dapat saya pikirkan adalah JSONException dari json.org, yang merupakan pengecualian yang diperiksa dan sebagian besar menyebalkan - seharusnya tidak dicentang, tetapi pengembang tidak memikirkannya.

Ngomong-ngomong, sebagian besar waktu minat penelepon dalam pengecualian secara langsung berkorelasi dengan kemampuan untuk pulih dari pengecualian, tetapi itu tidak selalu terjadi.


13

Berikut adalah solusi yang sangat sederhana untuk dilema Checked / Unchecked Anda.

Aturan 1: Pikirkan Pengecualian Tidak Dicentang sebagai kondisi yang dapat diuji sebelum kode dijalankan. sebagai contoh…

x.doSomething(); // the code throws a NullPointerException

di mana x adalah null ... ... kode mungkin harus memiliki yang berikut ...

if (x==null)
{
    //do something below to make sure when x.doSomething() is executed, it won’t throw a NullPointerException.
    x = new X();
}
x.doSomething();

Aturan 2: Pikirkan Pengecualian yang Diperiksa sebagai kondisi yang tidak dapat diuji yang mungkin terjadi saat kode dijalankan.

Socket s = new Socket(“google.com”, 80);
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();

... dalam contoh di atas, URL (google.com) mungkin tidak tersedia karena server DNS sedang tidak aktif. Bahkan saat ini server DNS sedang bekerja dan menyelesaikan nama 'google.com' ke alamat IP, jika koneksi dibuat ke google.com, kapan saja kata penutup, jaringan bisa turun. Anda tidak bisa menguji jaringan sepanjang waktu sebelum membaca dan menulis ke stream.

Ada saat-saat di mana kode harus dijalankan sebelum kita tahu jika ada masalah. Dengan memaksa pengembang untuk menulis kode mereka sedemikian rupa sehingga memaksa mereka untuk menangani situasi ini melalui Checked Exception, saya harus memberikan topi kepada pencipta Jawa yang menemukan konsep ini.

Secara umum, hampir semua API di Jawa mengikuti 2 aturan di atas. Jika Anda mencoba menulis ke file, disk dapat diisi sebelum menyelesaikan penulisan. Ada kemungkinan bahwa proses lain telah menyebabkan disk menjadi penuh. Tidak ada cara untuk menguji situasi ini. Bagi mereka yang berinteraksi dengan perangkat keras di mana kapan saja, menggunakan perangkat keras dapat gagal, Pengecualian Tercatat tampaknya menjadi solusi yang elegan untuk masalah ini.

Ada area abu-abu untuk ini. Jika diperlukan banyak tes (pikiran bertiup jika pernyataan dengan banyak && dan ||), pengecualian yang dilemparkan akan menjadi CheckedException hanya karena terlalu banyak rasa sakit untuk diperbaiki - Anda tidak bisa mengatakan masalah ini adalah kesalahan pemrograman. Jika ada jauh lebih sedikit dari 10 tes (misalnya 'jika (x == null)'), maka kesalahan pemrogram harus berupa UncheckedException.

Banyak hal menjadi menarik ketika berhadapan dengan penerjemah bahasa. Menurut aturan di atas, haruskah Kesalahan Sintaks dianggap sebagai Pengecualian yang Dicentang atau Tidak Dicentang? Saya berpendapat bahwa jika sintaks bahasa dapat diuji sebelum dieksekusi, itu harus menjadi UncheckedException. Jika bahasa tidak dapat diuji - mirip dengan bagaimana kode assembly berjalan di komputer pribadi, maka Kesalahan Sintaksis seharusnya menjadi Pengecualian yang Diperiksa.

2 aturan di atas mungkin akan menghapus 90% kekhawatiran Anda untuk memilih. Untuk meringkas aturan, ikuti pola ini ... 1) jika kode yang akan dieksekusi dapat diuji sebelum dieksekusi agar dapat berjalan dengan benar dan jika suatu Pengecualian terjadi - alias kesalahan pemrogram, Pengecualian harus berupa UncheckedException (subkelas RuntimeException ). 2) jika kode yang akan dieksekusi tidak dapat diuji sebelum dijalankan agar benar, Pengecualian harus menjadi Pengecualian yang Diperiksa (subkelas Pengecualian).


9

Anda dapat menyebutnya pengecualian yang dicentang atau tidak dicentang; namun, kedua jenis pengecualian dapat ditangkap oleh programmer, jadi jawaban terbaik adalah: tulis semua pengecualian Anda sebagai tidak dicentang dan dokumentasikan. Dengan begitu pengembang yang menggunakan API Anda dapat memilih apakah ia ingin menangkap pengecualian itu dan melakukan sesuatu. Pengecualian yang diperiksa benar-benar menghabiskan waktu semua orang dan itu membuat kode Anda mimpi buruk yang mengejutkan untuk dilihat. Pengujian unit yang tepat akan memunculkan pengecualian yang mungkin harus Anda tangkap dan lakukan sesuatu.


1
+1 Untuk menyebutkan bahwa tes unit mungkin merupakan cara yang lebih baik untuk menyelesaikan masalah, pengecualian yang dimaksudkan untuk diselesaikan adalah masalah.
Keith Pinson

+1 untuk pengujian unit. Menggunakan Pengecekan Tercek / Tak Terkecualikan berdampak kecil pada kualitas kode. Jadi argumen bahwa jika seseorang menggunakan pengecualian diperiksa akan menghasilkan kualitas kode yang lebih baik adalah argumen palsu lengkap!
user1697575

7

Pengecualian yang Dicentang: Jika klien dapat memulihkan dari pengecualian dan ingin melanjutkan, gunakan pengecualian yang diperiksa.

Pengecualian tidak dicentang: Jika klien tidak dapat melakukan apa pun setelah pengecualian, maka angkat pengecualian yang tidak dicentang.

Contoh: Jika Anda diharapkan untuk melakukan operasi aritmatika dalam metode A () dan berdasarkan pada output dari A (), Anda harus ke operasi lain. Jika outputnya nol dari metode A () yang tidak Anda harapkan selama run time, maka Anda diharapkan untuk melempar Null pointer Exception yang merupakan pengecualian Run time.

Rujuk ke sini


2

Saya setuju dengan preferensi untuk pengecualian yang tidak dicentang sebagai aturan, terutama ketika merancang API. Penelepon selalu dapat memilih untuk menangkap pengecualian yang didokumentasikan dan tidak dicentang. Anda hanya tidak perlu memaksa penelepon untuk.

Saya menemukan pengecualian yang diperiksa bermanfaat di tingkat bawah, sebagai detail implementasi. Ini sering tampak seperti aliran mekanisme kontrol yang lebih baik daripada harus mengelola kesalahan "kode pengembalian" yang ditentukan. Kadang-kadang dapat membantu melihat dampak ide untuk perubahan kode tingkat rendah juga ... menyatakan pengecualian diperiksa dan melihat siapa yang perlu menyesuaikan. Poin terakhir ini tidak berlaku jika ada banyak generik: catch (Exception e) atau throws Exception yang biasanya tidak dipikirkan dengan baik pula.


2

Di sini saya ingin membagikan pendapat saya setelah bertahun-tahun pengalaman pengembangan:

  1. Pengecualian diperiksa. Ini adalah bagian dari kasus penggunaan bisnis atau aliran panggilan, ini adalah bagian dari logika aplikasi yang kami harapkan atau tidak harapkan. Misalnya koneksi ditolak, kondisinya tidak memuaskan dll. Kita perlu menanganinya dan menunjukkan pesan yang sesuai kepada pengguna dengan instruksi apa yang terjadi dan apa yang harus dilakukan selanjutnya (coba lagi nanti, dll). Saya biasanya menyebutnya pengecualian pasca-pemrosesan atau pengecualian "pengguna".

  2. Pengecualian tidak dicentang. Ini adalah bagian dari pengecualian pemrograman, beberapa kesalahan dalam pemrograman kode perangkat lunak (bug, cacat) dan mencerminkan cara bagaimana programmer harus menggunakan API sesuai dokumentasi. Jika dokumen eksternal lib / framework mengatakan mereka mengharapkan untuk mendapatkan data dalam beberapa rentang dan non null, karena NPE atau IllegalArgumentException akan dilempar, programmer harus mengharapkannya dan menggunakan API dengan benar sesuai dokumentasi. Kalau tidak, pengecualian akan dibuang. Saya biasanya menyebutnya pengecualian pra-pemrosesan atau pengecualian "validasi".

Oleh audiens target. Sekarang mari kita bicara tentang audiens target atau sekelompok orang pengecualian telah dirancang (sesuai pendapat saya):

  1. Pengecualian diperiksa. Target audiens adalah pengguna / klien.
  2. Pengecualian tidak dicentang. Target pengguna adalah pengembang. Dengan kata lain pengecualian tidak dicentang dirancang hanya untuk pengembang.

Dengan fase siklus pengembangan pengembangan aplikasi.

  1. Pengecualian diperiksa dirancang untuk ada selama seluruh siklus hidup produksi sebagai mekanisme normal dan diharapkan aplikasi menangani kasus luar biasa.
  2. Pengecualian yang tidak dicentang dirancang untuk ada hanya selama pengembangan aplikasi / pengujian siklus hidup, semuanya harus diperbaiki selama waktu itu dan tidak boleh dibuang ketika aplikasi sudah berjalan pada produksi sudah.

Alasan mengapa kerangka kerja biasanya menggunakan pengecualian yang tidak dicentang (misalnya Spring) adalah bahwa kerangka kerja tidak dapat menentukan logika bisnis aplikasi Anda, ini tergantung pada pengembang untuk menangkapnya dan merancang logika sendiri.


2

Kita harus membedakan kedua jenis pengecualian ini berdasarkan apakah itu kesalahan programmer atau bukan.

  • Jika kesalahan adalah kesalahan programmer, itu harus Pengecualian Tidak Dicentang . Misalnya: SQLException / IOException / NullPointerException. Pengecualian ini adalah kesalahan pemrograman. Mereka harus ditangani oleh programmer. Sementara di JDBC API, SQLException Diperiksa Pengecualian, Pada Musim Semi JDBCTemplate ini adalah Pengecualian Tidak Dicentang. Programmer tidak khawatir tentang SqlException, saat menggunakan Spring.
  • Jika kesalahan bukan kesalahan pemrogram dan alasannya berasal dari luar, itu harus merupakan Pengecualian yang Diperiksa. Misalnya: jika file dihapus atau izin file diubah oleh orang lain, itu harus dipulihkan.

FileNotFoundException adalah contoh yang baik untuk memahami perbedaan yang halus. FileNotFoundException dilemparkan seandainya file tidak ditemukan. Ada dua alasan untuk pengecualian ini. Jika jalur file ditentukan oleh pengembang atau mengambil dari pengguna akhir melalui GUI itu harus menjadi Pengecualian Tidak Dicentang. Jika file dihapus oleh orang lain, itu haruslah Pengecualian yang Diperiksa.

Pengecualian yang Diperiksa dapat ditangani dengan dua cara. Ini menggunakan try-catch atau menyebarkan pengecualian. Dalam kasus penyebaran pengecualian, semua metode dalam tumpukan panggilan akan digabungkan dengan erat karena penanganan pengecualian. Karena itu, kita harus menggunakan Checked Exception dengan hati-hati.

Jika Anda mengembangkan sistem perusahaan berlapis, Anda harus memilih sebagian besar pengecualian yang tidak dicentang untuk dibuang, tetapi jangan lupa untuk menggunakan pengecualian yang sudah diperiksa untuk kasus yang tidak dapat Anda lakukan apa pun.


1

Pengecualian yang diperiksa berguna untuk kasus-kasus yang dapat dipulihkan di mana Anda ingin memberikan informasi kepada pemanggil (mis. Izin yang tidak mencukupi, file tidak ditemukan, dll).

Pengecualian yang tidak dicentang jarang digunakan, jika sama sekali, untuk memberi tahu pengguna atau pemrogram tentang kesalahan serius atau kondisi tak terduga selama waktu berjalan. Jangan membuangnya jika Anda menulis kode atau pustaka yang akan digunakan oleh orang lain, karena mereka mungkin tidak mengharapkan perangkat lunak Anda untuk melemparkan pengecualian yang tidak dicentang karena kompiler tidak memaksa mereka untuk ditangkap atau dideklarasikan.


Saya tidak setuju dengan pernyataan Anda "Pengecualian yang tidak dicentang jarang digunakan, jika sama sekali" sebenarnya itu harus berlawanan! Gunakan exceprions yang tidak dicentang secara default saat Anda mendesain hierarki pengecualian aplikasi Anda. Biarkan pengembang untuk memutuskan kapan mereka ingin menangani pengecualian (misalnya mereka tidak dipaksa untuk menempatkan blok penangkap atau menempatkan klausa melempar jika mereka tidak tahu bagaimana menanganinya).
user1697575

1

Jika ada perkecualian yang kurang diharapkan, dan kami dapat melanjutkan bahkan setelah menangkapnya, dan kami tidak dapat melakukan apa pun untuk menghindari pengecualian itu maka kami dapat menggunakan pengecualian yang dicentang.

Setiap kali kita ingin melakukan sesuatu yang berarti ketika pengecualian tertentu terjadi dan ketika pengecualian itu diharapkan tetapi tidak pasti, maka kita dapat menggunakan pengecualian yang diperiksa.

Kapan pun pengecualian bernavigasi di lapisan yang berbeda, kami tidak perlu menangkapnya di setiap lapisan, dalam hal ini, kami dapat menggunakan pengecualian runtime atau membungkus pengecualian sebagai pengecualian yang tidak dicentang.

Pengecualian runtime digunakan ketika pengecualian yang paling mungkin terjadi, tidak ada cara untuk melangkah lebih jauh dan tidak ada yang bisa dipulihkan. Jadi dalam hal ini kita dapat mengambil tindakan pencegahan sehubungan dengan pengecualian itu. EX: NUllPointerException, ArrayOutofBoundsException. Ini lebih mungkin terjadi. Dalam skenario ini, kita dapat mengambil tindakan pencegahan saat pengkodean untuk menghindari pengecualian tersebut. Kalau tidak, kita harus menulis coba tangkap blok di mana-mana.

Pengecualian yang lebih umum dapat dibuat Tidak dicentang, kurang umum dicek.


1

Saya pikir kita dapat memikirkan pengecualian dari beberapa pertanyaan:

mengapa pengecualian terjadi? Apa yang bisa kita lakukan ketika itu terjadi

karena kesalahan, bug. seperti metode objek null disebut.

String name = null;
... // some logics
System.out.print(name.length()); // name is still null here

Pengecualian semacam ini harus diperbaiki selama pengujian. Kalau tidak, itu merusak produksi, dan Anda mendapat bug yang sangat tinggi yang perlu segera diperbaiki. Pengecualian semacam ini tidak perlu diperiksa.

dengan input dari eksternal, Anda tidak dapat mengontrol atau memercayai output dari layanan eksternal.

String name = ExternalService.getName(); // return null
System.out.print(name.length());    // name is null here

Di sini, Anda mungkin perlu memeriksa apakah nama itu nol jika Anda ingin melanjutkan ketika itu nol, jika tidak, Anda bisa membiarkannya sendirian dan itu akan berhenti di sini dan memberikan penelepon pengecualian runtime. Pengecualian semacam ini tidak perlu diperiksa.

dengan pengecualian runtime dari eksternal, Anda tidak dapat mengontrol atau mempercayai layanan eksternal.

Di sini, Anda mungkin perlu menangkap semua pengecualian dari ExternalService jika Anda ingin melanjutkan ketika itu terjadi, jika tidak, Anda bisa membiarkannya sendiri dan itu akan berhenti di sini dan memberikan penelepon pengecualian runtime.

dengan mengecek pengecualian dari eksternal, Anda tidak dapat mengontrol atau memercayai layanan eksternal.

Di sini, Anda mungkin perlu menangkap semua pengecualian dari ExternalService jika Anda ingin melanjutkan ketika itu terjadi, jika tidak, Anda bisa membiarkannya sendiri dan itu akan berhenti di sini dan memberikan penelepon pengecualian runtime.

Dalam hal ini, apakah kita perlu tahu pengecualian apa yang terjadi di ExternalService? Tergantung:

  1. jika Anda dapat menangani beberapa jenis pengecualian, Anda perlu menangkapnya dan memprosesnya. Bagi yang lain, gembungkan mereka.

  2. jika Anda memerlukan log atau respons kepada pengguna eksekusi spesifik, Anda dapat menangkapnya. Bagi yang lain, gembungkan mereka.


0

Saya pikir ketika menyatakan Pengecualian Aplikasi harus Pengecualian tidak dicentang yaitu, subkelas RuntimeException. Alasannya adalah tidak akan mengacaukan kode aplikasi dengan try-catch dan melempar deklarasi pada metode. Jika aplikasi Anda menggunakan Java Api yang melempar pengecualian diperiksa yang anyways perlu ditangani. Untuk kasus lain, aplikasi dapat membuang pengecualian yang tidak dicentang. Jika pemanggil aplikasi masih perlu menangani pengecualian yang tidak dicentang, itu bisa dilakukan.


-12

Aturan yang saya gunakan adalah: jangan pernah menggunakan pengecualian yang tidak dicentang! (atau ketika Anda tidak melihat jalan keluar)

Dari sudut pandang pengembang yang menggunakan perpustakaan Anda atau pengguna akhir yang menggunakan perpustakaan Anda / aplikasi itu benar-benar menyebalkan untuk dihadapkan dengan aplikasi yang crash karena pengecualian yang tidak dipikirkan. Dan mengandalkan tangkapan-semua juga tidak baik.

Dengan cara ini pengguna akhir masih dapat disajikan dengan pesan kesalahan, alih-alih aplikasi benar-benar menghilang.


1
Anda tidak menjelaskan apa yang menurut Anda salah dengan tangkapan-semua untuk sebagian besar pengecualian yang tidak dicentang.
Matthew Flaschen

Sepenuhnya tidak setuju dengan jawaban Anda yang tidak diperdebatkan: "tidak pernah menggunakan pengecualian yang tidak dicentang"
user1697575
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.