Memahami pengecualian diperiksa dan tidak dicentang di Jawa

703

Joshua Bloch dalam " Java Efektif " mengatakan itu

Gunakan pengecualian yang dicentang untuk kondisi yang dapat dipulihkan dan pengecualian runtime untuk kesalahan pemrograman (Butir 58 dalam edisi kedua)

Mari kita lihat apakah saya mengerti ini dengan benar.

Inilah pemahaman saya tentang pengecualian yang diperiksa:

try{
    String userInput = //read in user input
    Long id = Long.parseLong(userInput);
}catch(NumberFormatException e){
    id = 0; //recover the situation by setting the id to 0
}

1. Apakah hal di atas dianggap sebagai pengecualian yang diperiksa?

2. Apakah RuntimeException merupakan pengecualian yang tidak dicentang?

Inilah pemahaman saya tentang pengecualian yang tidak dicentang:

try{
    File file = new File("my/file/path");
    FileInputStream fis = new FileInputStream(file);   
}catch(FileNotFoundException e){

//3. What should I do here?
    //Should I "throw new FileNotFoundException("File not found");"?
    //Should I log?
    //Or should I System.exit(0);?
}

4. Sekarang, bukankah kode di atas juga bisa menjadi pengecualian yang diperiksa? Saya dapat mencoba memulihkan situasi seperti ini? Bisakah saya? (Catatan: pertanyaan ketiga saya ada di dalam di catchatas)

try{
    String filePath = //read in from user input file path
    File file = new File(filePath);
    FileInputStream fis = new FileInputStream(file);   
}catch(FileNotFoundException e){
    //Kindly prompt the user an error message
    //Somehow ask the user to re-enter the file path.
}

5. Mengapa orang melakukan ini?

public void someMethod throws Exception{

}

Mengapa mereka membiarkan pengecualian muncul? Bukankah penanganan kesalahan lebih cepat lebih baik? Mengapa menggembung?

6. Haruskah saya menggembungkan pengecualian yang tepat atau menyembunyikannya menggunakan Pengecualian?

Di bawah ini adalah bacaan saya

Di Jawa, kapan saya harus membuat pengecualian yang diperiksa, dan kapan itu harus menjadi pengecualian runtime?

Kapan memilih pengecualian yang dicentang dan tidak dicentang

Thang Pham
sumber
6
Saya memiliki contoh pengecualian yang tidak terkendali. Saya memiliki DataSerieskelas yang menyimpan data yang selalu harus tetap dalam urutan berdasarkan waktu. Ada metode untuk menambahkan yang baru DataPointke akhir a DataSeries. Jika semua kode saya berfungsi dengan baik di seluruh proyek, DataPointjangan pernah ditambahkan ke bagian akhir yang memiliki tanggal sebelumnya dengan yang sudah ada di bagian akhir. Setiap modul di seluruh proyek dibangun dengan disangkal ini. Namun, saya memeriksa kondisi ini dan melemparkan pengecualian yang tidak dicentang jika itu terjadi. Mengapa? Jika itu terjadi, saya ingin tahu siapa yang melakukan ini dan memperbaikinya.
Erick Robertson
3
Untuk menambah lebih banyak kebingungan. Banyak orang menganjurkan pengecualian diperiksa ~ 10 tahun yang lalu, tetapi pandangan hari ini semakin bergerak menuju "pengecualian diperiksa adalah buruk". (Namun saya tidak setuju tentang itu)
Kaj
10
Ini hanya berguna untuk menangani Pengecualian ketika Anda memiliki sesuatu yang berguna untuk dilakukan dengan itu, jika tidak, Anda harus membiarkan penelepon menanganinya. Mencatatnya dan berpura-pura itu tidak terjadi biasanya tidak bermanfaat. Hanya melempar kembali itu tidak ada gunanya. Membungkus RuntimeException tidak berguna seperti yang dipikirkan beberapa orang, itu hanya membuat kompiler berhenti membantu Anda. (IMHO)
Peter Lawrey
40
Kita harus berhenti menggunakan ketentuan yang menyesatkan secara komprehensif dari pengecualian yang diperiksa / tidak dicentang . Mereka harus disebut pengecualian cek-mandat vs cek-tidak-mandat .
Blessed Geek
3
Saya juga berpikir tentang vv public point 5 method_name publics throws Exception {} mengapa beberapa orang melakukan itu?
Maveň ツ

Jawaban:

474

Banyak orang mengatakan bahwa pengecualian yang diperiksa (yaitu ini yang harus Anda tangkap atau rethrow secara eksplisit) tidak boleh digunakan sama sekali. Mereka dihilangkan dalam C # misalnya, dan sebagian besar bahasa tidak memilikinya. Jadi, Anda selalu dapat melempar subkelas RuntimeException(pengecualian yang tidak dicentang)

Namun, saya pikir pengecualian yang diperiksa berguna - mereka digunakan ketika Anda ingin memaksa pengguna API Anda untuk berpikir bagaimana menangani situasi yang luar biasa (jika itu dapat dipulihkan). Hanya saja pengecualian yang diperiksa digunakan secara berlebihan di platform Java, yang membuat orang membenci mereka.

Inilah pandangan saya tentang topik ini .

Adapun pertanyaan-pertanyaan khusus:

  1. Apakah NumberFormatExceptionmempertimbangkan pengecualian yang diperiksa?
    Tidak. Tidak NumberFormatExceptiondicentang (= subkelas dari RuntimeException). Mengapa? Saya tidak tahu (tapi seharusnya ada metode isValidInteger(..))

  2. Apakah RuntimeExceptionpengecualian tidak dicentang?
    Ya persis.

  3. Apa yang harus saya lakukan di sini?
    Tergantung di mana kode ini dan apa yang Anda inginkan terjadi. Jika berada di lapisan UI - tangkap dan tunjukkan peringatan; jika itu ada di lapisan layanan - jangan tangkap sama sekali - biarkan menggelembung. Hanya saja, jangan menelan pengecualian. Jika pengecualian terjadi di sebagian besar kasus, Anda harus memilih salah satu dari ini:

    • login dan kembali
    • rethrow itu (menyatakan itu untuk dilemparkan oleh metode)
    • membangun pengecualian baru dengan melewatkan yang sekarang di konstruktor
  4. Sekarang, tidak bisakah kode di atas juga merupakan pengecualian yang diperiksa? Saya dapat mencoba memulihkan situasi seperti ini? Bisakah saya?
    Itu bisa saja. Tapi tidak ada yang menghentikan Anda untuk menangkap pengecualian yang tidak diperiksa

  5. Mengapa orang menambahkan kelas Exceptiondalam klausa pelemparan?
    Paling sering karena orang malas untuk mempertimbangkan apa yang harus ditangkap dan apa yang harus dipikirkan kembali. Melempar Exceptionadalah praktik yang buruk dan harus dihindari.

Sayangnya, tidak ada aturan tunggal yang memungkinkan Anda menentukan kapan harus menangkap, kapan harus rethrow, kapan harus menggunakan dicentang dan kapan harus menggunakan pengecualian yang tidak dicentang. Saya setuju ini menyebabkan banyak kebingungan dan banyak kode buruk. Prinsip umum dinyatakan oleh Bloch (Anda mengutip sebagian darinya). Dan prinsip umum adalah untuk memikirkan kembali pengecualian pada lapisan di mana Anda bisa menanganinya.

Bozho
sumber
36
Mengenai melempar Pengecualian, itu tidak selalu karena orang malas, itu juga umum bahwa Anda, ketika Anda menerapkan kerangka kerja, biarkan pengguna kerangka kerja dapat membuang pengecualian. Anda dapat misalnya memeriksa tanda tangan antarmuka Callable di JSE
Kaj
10
@ Kaj - ya, hal-hal umum seperti Callable, pencegat dan sejenisnya adalah kasus khusus. Tetapi dalam kebanyakan kasus itu karena orang-orang malas :)
Bozho
7
re: 3.1 "catat dan kembalikan" Lakukan dengan bijak. Ini sangat dekat dengan makan atau bersembunyi dan pengecualian. Saya akan melakukan ini untuk sesuatu yang tidak menunjukkan masalah, itu tidak benar-benar luar biasa. Log kebanjiran dan diabaikan dengan mudah.
Chris
4
"ketika Anda ingin memaksa pengguna API Anda untuk berpikir bagaimana menangani situasi yang luar biasa" - Anda tidak dapat memaksa siapa pun untuk berpikir jika mereka tidak mau. Jika mereka tidak mau berpikir, mereka akan menulis blok pengecualian yang buruk yang tidak melakukan apa-apa, atau lebih buruk, menghapus atau mengganggu informasi kesalahan kritis. Itulah sebabnya pengecualian yang diperiksa adalah kegagalan.
adrianos
3
@adrianos "... Anda tidak dapat memaksa siapa pun untuk berpikir jika mereka tidak ingin ...." Dengan alur pemikiran ini kami juga dapat menghapus kesalahan kompilasi .... Saya tidak benar-benar menargetkan Anda, saya pernah mendengar ini argumen berulang kali dan masih menemukan itu sebagai penjelasan termiskin untuk melabeli Pengecualian yang Dicek sebagai kegagalan. Sebagai catatan, saya telah melihat sebelumnya bahasa di mana kompilasi (dan kesalahan runtime juga sebenarnya) secara efektif dibuat tidak mungkin dengan desing. Jalan itu menuju ke beberapa tempat yang sangat gelap.
Newtopian
233

Apakah sesuatu merupakan "pengecualian yang diperiksa" tidak ada hubungannya dengan apakah Anda menangkapnya atau apa yang Anda lakukan di blok tangkap. Ini properti kelas pengecualian. Apa pun yang merupakan subkelas Exception kecuali untuk RuntimeExceptiondan subkelasnya adalah pengecualian yang diperiksa.

Kompiler Java memaksa Anda untuk menangkap pengecualian yang dicentang atau mendeklarasikannya dalam tanda tangan metode. Seharusnya meningkatkan keamanan program, tetapi pendapat mayoritas tampaknya tidak sebanding dengan masalah desain yang dibuatnya.

Mengapa mereka membiarkan pengecualian muncul? Bukankah menangani kesalahan semakin cepat semakin baik? Mengapa menggembung?

Karena itulah seluruh titik pengecualian. Tanpa kemungkinan ini, Anda tidak perlu pengecualian. Mereka memungkinkan Anda untuk menangani kesalahan pada tingkat yang Anda pilih, alih-alih memaksa Anda untuk menanganinya dalam metode tingkat rendah di mana mereka awalnya terjadi.

Michael Borgwardt
sumber
3
Terima kasih! Saya kadang-kadang membuang pengecualian dari metode saya karena prinsip omong kosong omong kosong. Saya salah satu pengembang di tim saya ingin memasukkan ekspresi xpath yang tidak valid terserah mereka untuk menangani pengecualian. Dalam hal yang tidak terduga mereka menangkap pengecualian dan tidak melakukan apa pun yang akan mereka dengar dalam ulasan kode.
jeremyjjbrown
12
"Apa pun yang merupakan subkelas Throwable kecuali untuk RuntimeException dan subkelasnya adalah pengecualian yang sudah diperiksa." - Pernyataan Anda salah. Kesalahan juga mewarisi Throwable dan tidak dicentang.
Bartzilla
8
@JonasEicher: pada dasarnya, keuntungan utama dari pengecualian adalah mereka memungkinkan Anda memilih di mana dalam tumpukan panggilan Anda ingin menangani kesalahan, yang seringkali cukup tinggi, sambil menjaga lapisan di antara benar-benar bebas dari artefak penanganan kesalahan. Pengecualian yang diperiksa menghancurkan persis keuntungan itu. Masalah lain adalah bahwa pembedaan yang dicentang / tidak dicentang terkait dengan kelas pengecualian yang juga mewakili kategorisasi pengecualian secara konseptual - menggabungkan dua aspek yang tidak harus terkait sama sekali.
Michael Borgwardt
2
"Tapi pendapat mayoritas tampaknya tidak sepadan dengan masalah desain yang diciptakannya." - Kutipan silakan?
kervin
3
@Bartzilla Ya. Untuk kelengkapan, seperti kata javadoc untuk Throwable: "Throwable dan subclass dari Throwable yang bukan juga subclass dari RuntimeException atau Error dianggap sebagai pengecualian yang dicek"
Bart van Heukelom
74
  1. Apakah hal di atas dianggap sebagai pengecualian yang diperiksa? Tidak. Fakta bahwa Anda menangani pengecualian tidak membuatnya menjadi Checked Exceptionjika itu adalah RuntimeException.

  2. Apakah RuntimeExceptionitu unchecked exception? Iya

Checked Exceptionsadalah subclassesdari java.lang.Exception Unchecked Exceptionsyang subclassesdarijava.lang.RuntimeException

Panggilan yang melempar pengecualian yang diperiksa harus dimasukkan dalam blok coba {} atau ditangani pada level di atas dalam pemanggil metode. Dalam hal ini metode saat ini harus menyatakan bahwa ia melempar pengecualian tersebut sehingga penelepon dapat membuat pengaturan yang tepat untuk menangani pengecualian.

Semoga ini membantu.

T: apakah saya harus melembungkan pengecualian yang tepat atau menutupinya menggunakan Pengecualian?

A: Ya ini pertanyaan yang sangat bagus dan pertimbangan desain yang penting. Pengecualian kelas adalah kelas pengecualian yang sangat umum dan dapat digunakan untuk membungkus pengecualian tingkat rendah internal. Anda akan lebih baik membuat pengecualian khusus dan membungkus di dalamnya. Tapi, dan yang besar - Jangan pernah mengaburkan dalam akar penyebab asli yang mendasarinya. Sebagai contoh, Don't everlakukan hal berikut -

try {
     attemptLogin(userCredentials);
} catch (SQLException sqle) {
     throw new LoginFailureException("Cannot login!!"); //<-- Eat away original root cause, thus obscuring underlying problem.
}

Alih-alih lakukan hal berikut:

try {
     attemptLogin(userCredentials);
} catch (SQLException sqle) {
     throw new LoginFailureException(sqle); //<-- Wrap original exception to pass on root cause upstairs!.
}

Menghilangkan akar penyebab asli mengubur penyebab sebenarnya di luar pemulihan adalah mimpi buruk bagi tim dukungan produksi di mana semua mereka diberi akses adalah log aplikasi dan pesan kesalahan. Meskipun yang terakhir adalah desain yang lebih baik tetapi banyak orang tidak menggunakannya sering karena pengembang hanya gagal menyampaikan pesan yang mendasarinya kepada pemanggil. Jadi buatlah catatan tegas: Always pass on the actual exceptionkembali apakah dibungkus dengan aplikasi spesifik atau tidak.

Saat mencoba-tangkap RuntimeExceptions

RuntimeExceptions sebagai aturan umum tidak boleh dicoba. Mereka umumnya menandakan kesalahan pemrograman dan harus dibiarkan sendiri. Sebaliknya programmer harus memeriksa kondisi kesalahan sebelum memohon beberapa kode yang mungkin menghasilkan a RuntimeException. Misalnya:

try {
    setStatusMessage("Hello Mr. " + userObject.getName() + ", Welcome to my site!);
} catch (NullPointerException npe) {
   sendError("Sorry, your userObject was null. Please contact customer care.");
}

Ini adalah praktik pemrograman yang buruk. Alih-alih, pemeriksaan nol seharusnya dilakukan seperti -

if (userObject != null) {
    setStatusMessage("Hello Mr. " + userObject.getName() + ", Welome to my site!);
} else {
   sendError("Sorry, your userObject was null. Please contact customer care.");
}

Tapi ada kalanya pengecekan error semacam itu mahal seperti pemformatan angka, pertimbangkan ini -

try {
    String userAge = (String)request.getParameter("age");
    userObject.setAge(Integer.parseInt(strUserAge));
} catch (NumberFormatException npe) {
   sendError("Sorry, Age is supposed to be an Integer. Please try again.");
}

Di sini pemeriksaan kesalahan sebelum pemanggilan tidak sepadan dengan usaha karena pada dasarnya berarti menduplikasi semua kode konversi string-ke-integer di dalam metode parseInt () - dan rentan kesalahan jika diterapkan oleh pengembang. Jadi lebih baik untuk menyingkirkan try-catch.

Jadi NullPointerExceptiondan NumberFormatExceptionkeduanya RuntimeExceptions, menangkap NullPointerExceptionharus diganti dengan cek kosong anggun sementara saya merekomendasikan menangkap secara NumberFormatExceptioneksplisit untuk menghindari kemungkinan pengenalan kode rawan kesalahan.

d-live
sumber
Terima kasih. Satu pertanyaan lagi ketika Anda menggelembungkan exception, haruskah saya melembungkan pengecualian yang tepat atau menyembunyikannya menggunakan Exception. Saya menulis kode di atas beberapa kode warisan, dan Exceptiondigelembungkan di semua tempat. Saya ingin tahu apakah ini perilaku yang benar?
Thang Pham
1
Ini adalah pertanyaan yang sangat bagus dan penting, edit jawaban saya untuk memasukkan penjelasan.
d-live
Terima kasih banyak. Apakah mungkin bagi Anda untuk menunjukkan kepada saya konten LoginFailureException(sqle)?
Thang Pham
1
Saya tidak punya kode untuk hal-hal itu, saya hanya memasak nama-nama dll. Jika Anda melihat java.lang.Exception, ia memiliki 4 konstruktor dua di antaranya menerima java.lang.Throwable. Dalam cuplikan di atas saya mengasumsikan LoginFailureExceptionmeluas Exceptiondan mendeklarasikan konstruktorpublic LoginFailureException(Throwable cause) { super(cause) }
d-live
Jawaban terbaik tentang topik ini. Saya pikir pengecualian runtime tidak boleh ditangkap karena pengecualian ini terjadi karena kurangnya pemrograman yang baik. Saya sepenuhnya setuju dengan bagian "Makan akar penyebab asli mengubur penyebab sebenarnya setelah pemulihan adalah mimpi buruk bagi tim pendukung produksi di mana semua mereka diberi akses adalah log aplikasi dan pesan kesalahan.".
huseyin
19

1. Jika Anda tidak yakin tentang pengecualian, periksa API:

 java.lang.Object
 extended by java.lang.Throwable
  extended by java.lang.Exception
   extended by java.lang.RuntimeException  //<-NumberFormatException is a RuntimeException  
    extended by java.lang.IllegalArgumentException
     extended by java.lang.NumberFormatException

2. Ya, dan setiap pengecualian yang memperpanjangnya.

3. Tidak perlu menangkap dan melempar pengecualian yang sama. Anda dapat menampilkan Dialog File baru dalam kasus ini.

4. FileNotFoundException adalah sudah pengecualian diperiksa.

5. Jika diharapkan memanggil metode someMethoduntuk menangkap pengecualian, yang terakhir dapat dibuang. Itu hanya "mengoper bola". Contoh penggunaannya adalah jika Anda ingin membuangnya dalam metode pribadi Anda sendiri, dan menangani pengecualian dalam metode publik Anda sebagai gantinya.

Bacaan yang bagus adalah Oracle doc itu sendiri: http://download.oracle.com/javase/tutorial/essential/exceptions/runtime.html

Mengapa para perancang memutuskan untuk memaksakan suatu metode untuk menetapkan semua pengecualian yang tidak diperiksa yang dapat dilemparkan ke dalam cakupannya? Pengecualian apa pun yang dapat dilemparkan oleh suatu metode adalah bagian dari antarmuka pemrograman publik metode tersebut. Mereka yang memanggil metode harus tahu tentang pengecualian yang bisa dilemparkan metode sehingga mereka dapat memutuskan apa yang harus dilakukan tentang mereka. Pengecualian ini merupakan bagian dari antarmuka pemrograman metode itu sebagai parameter dan nilai kembali.

Pertanyaan berikutnya mungkin: "Jika dokumentasi metode API sangat bagus, termasuk pengecualian yang dapat dilontarkan, mengapa tidak menentukan pengecualian runtime juga?" Pengecualian runtime mewakili masalah yang merupakan hasil dari masalah pemrograman, dan karena itu, kode klien API tidak dapat diharapkan untuk pulih dari mereka atau untuk menanganinya dengan cara apa pun. Masalah tersebut termasuk pengecualian aritmatika, seperti membaginya dengan nol; pengecualian pointer, seperti mencoba mengakses objek melalui referensi nol; dan pengecualian pengindeksan, seperti mencoba mengakses elemen array melalui indeks yang terlalu besar atau terlalu kecil.

Ada juga sedikit informasi penting dalam Spesifikasi Bahasa Jawa :

Kelas pengecualian yang diperiksa yang disebutkan dalam klausa pelemparan adalah bagian dari kontrak antara implementor dan pengguna metode atau konstruktor .

Intinya IMHO adalah bahwa Anda dapat menangkap apa pun RuntimeException, tetapi Anda tidak diharuskan dan, pada kenyataannya implementasi tidak diperlukan untuk mempertahankan pengecualian yang tidak dicentang yang sama yang dilemparkan, karena itu bukan bagian dari kontrak.

Aleadam
sumber
Terima kasih. Satu pertanyaan lagi ketika Anda menggelembungkan exception, haruskah saya melembungkan pengecualian yang tepat atau menyembunyikannya menggunakan Exception. Saya menulis kode di atas beberapa kode warisan, dan Exceptiondigelembungkan di semua tempat. Saya ingin tahu apakah ini perilaku yang benar?
Thang Pham
1
@ Harry Saya akan membiarkan orang-orang dengan lebih banyak pengetahuan daripada saya untuk menjawab bahwa: stackoverflow.com/questions/409563/…
Aleadam
10

1) Tidak, NumberFormatException adalah Pengecualian yang tidak dicentang. Meskipun Anda menangkapnya (Anda tidak diharuskan) karena tidak dicentang. Ini karena itu adalah subkelas IllegalArgumentExceptionyang merupakan subkelas dari RuntimeException.

2) RuntimeExceptionadalah akar dari semua Pengecualian yang tidak dicentang. Setiap subkelas dari RuntimeExceptiontidak dicentang. Semua Pengecualian lainnya dan Throwablediperiksa kecuali untuk Kesalahan (Yang termasuk dalam Throwable).

3/4) Anda bisa memberi tahu pengguna bahwa mereka memilih file yang tidak ada dan meminta yang baru. Atau hanya berhenti memberi tahu pengguna bahwa mereka memasukkan sesuatu yang tidak valid.

5) Melempar dan menangkap 'Exception'adalah praktik yang buruk. Tetapi lebih umum, Anda bisa melempar pengecualian lain sehingga penelepon dapat memutuskan bagaimana menghadapinya. Misalnya, jika Anda menulis perpustakaan untuk menangani membaca beberapa input file dan metode Anda melewati file yang tidak ada, Anda tidak tahu bagaimana menanganinya. Apakah penelepon ingin bertanya lagi atau berhenti? Jadi Anda membuang Exception ke rantai kembali ke penelepon.

Dalam banyak kasus, suatu unchecked Exceptionterjadi karena programmer tidak memverifikasi input (dalam kasus NumberFormatExceptionpada pertanyaan pertama Anda). Itu sebabnya opsional untuk menangkap mereka, karena ada cara yang lebih elegan untuk menghindari menghasilkan pengecualian itu.

dontocsata
sumber
Terima kasih. Satu pertanyaan lagi ketika Anda menggelembungkan exception, haruskah saya melembungkan pengecualian yang tepat atau menyembunyikannya menggunakan Exception. Saya menulis kode di atas beberapa kode warisan, dan Exceptiondigelembungkan di semua tempat. Saya ingin tahu apakah ini perilaku yang benar?
Thang Pham
Anda dapat meminta metode Anda juga membuang Exception (yang tidak ideal). Atau tangkap Exception dan lemparkan Exception yang lebih baik (seperti IOException atau sesuatu). Semua Pengecualian dapat mengambil Pengecualian dalam konstruktor mereka sebagai 'penyebab', jadi Anda harus menggunakannya.
dontocsata
8

Diperiksa - Rawan terjadi. Diperiksa dalam waktu kompilasi.

Mis. Operasi File

Tidak Diperhatikan - Karena data buruk. Diperiksa dalam Run time.

Misalnya..

String s = "abc";
Object o = s;
Integer i = (Integer) o;

Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
    at Sample.main(Sample.java:9)

Di sini pengecualian disebabkan oleh data yang buruk dan tidak dapat ditentukan selama waktu kompilasi.

bharanitharan
sumber
6

Pengecualian yang diperiksa diperiksa pada waktu kompilasi oleh JVM dan terkait dengan sumber daya (file / db / stream / socket dll). Motif dari pengecualian yang diperiksa adalah bahwa pada waktu kompilasi jika sumber daya tidak tersedia, aplikasi harus mendefinisikan perilaku alternatif untuk menangani hal ini di blok tangkapan / akhirnya.

Pengecualian yang tidak dicentang adalah murni kesalahan program, perhitungan yang salah, data nol atau bahkan kegagalan dalam logika bisnis dapat menyebabkan pengecualian runtime. Benar-benar baik untuk menangani / menangkap pengecualian yang tidak dicentang dalam kode.

Penjelasan diambil dari http://coder2design.com/java-interview-questions/

Jatinder Pal
sumber
5

Deskripsi favorit mutlak saya tentang perbedaan antara pengecualian tidak dicentang dan dicentang disediakan oleh artikel jejak Tutorial Java, " Pengecualian tidak dicentang - Kontroversi " (maaf untuk mendapatkan semua dasar pada posting ini - tapi, hei, dasar-dasarnya kadang-kadang yang terbaik):

Inilah pedoman garis bawah: Jika klien dapat diharapkan pulih dari pengecualian, jadikan itu pengecualian yang dicentang. Jika klien tidak dapat melakukan apa pun untuk memulihkan dari pengecualian, jadikan itu pengecualian yang tidak dicentang

Inti dari "apa jenis pengecualian untuk melempar" adalah semantik (sampai taraf tertentu) dan kutipan di atas memberikan dan pedoman yang sangat baik (karenanya, saya masih terpesona oleh gagasan bahwa C # menyingkirkan pengecualian yang diperiksa - khususnya sebagaimana Liskov berpendapat untuk manfaatnya).

Sisanya kemudian menjadi logis: ke pengecualian mana kompilator mengharapkan saya untuk merespons, secara eksplisit? Yang Anda harapkan klien pulih.

Thomas
sumber
5

Untuk menjawab pertanyaan terakhir (yang lain tampaknya dijawab dengan tuntas di atas), "Haruskah saya melontarkan pengecualian yang tepat atau menyembunyikannya menggunakan Pengecualian?"

Saya berasumsi Anda bermaksud sesuatu seperti ini:

public void myMethod() throws Exception {
    // ... something that throws FileNotFoundException ...
}

Tidak, selalu nyatakan pengecualian yang setepat mungkin, atau daftar semacam itu. Pengecualian yang Anda nyatakan metode Anda mampu melempar adalah bagian dari kontrak antara metode Anda dan pemanggil. Melempar "FileNotFoundException"berarti ada kemungkinan nama file tidak valid dan file tidak akan ditemukan; penelepon harus menangani hal itu dengan cerdas. Melempar Exceptionberarti "Hei, dia tidak terjadi. Kesepakatan." Yang sangat miskin API.

Dalam komentar pada artikel pertama ada beberapa contoh di mana "melempar Exception" adalah deklarasi yang sah dan masuk akal, tetapi itu tidak berlaku untuk sebagian besar normalkode " " yang akan Anda tulis.

Tom Dibble
sumber
Tepatnya, jadikan deklarasi pengecualian cek Anda sebagai bagian dari dokumentasi kode Anda serta membantu orang yang menggunakan perangkat lunak Anda.
Salvador Valencia
5

Pengecualian Runtime : Pengecualian runtime disebut sebagai pengecualian yang tidak dicentang. Semua pengecualian lain diperiksa pengecualian, dan mereka tidak berasal dari java.lang.RuntimeException.

Pengecualian yang Dicentang : Pengecualian yang dicentang harus ditangkap di suatu tempat dalam kode Anda. Jika Anda memanggil metode yang melempar pengecualian yang diperiksa tetapi Anda tidak menangkap pengecualian yang dicentang di suatu tempat, kode Anda tidak akan dikompilasi. Itu sebabnya mereka disebut pengecualian diperiksa: kompilator memeriksa untuk memastikan bahwa mereka ditangani atau dideklarasikan.

Sejumlah metode di Java API melempar pengecualian yang diperiksa, jadi Anda akan sering menulis penangan pengecualian untuk mengatasi pengecualian yang dihasilkan oleh metode yang tidak Anda tulis.

Omer
sumber
3

Mengapa mereka membiarkan pengecualian muncul? Bukankah penanganan kesalahan lebih cepat lebih baik? Mengapa menggembung?

Sebagai contoh katakanlah Anda memiliki beberapa aplikasi client-server dan klien telah membuat permintaan untuk beberapa sumber daya yang tidak dapat ditemukan atau untuk sesuatu kesalahan lain beberapa mungkin terjadi di sisi server saat memproses permintaan pengguna maka itu adalah tugas dari server untuk memberi tahu klien mengapa dia tidak bisa mendapatkan hal yang dia minta, jadi untuk mencapai itu di sisi server, kode ditulis untuk melempar pengecualian menggunakan kata kunci throw alih-alih menelan atau menangani itu. jika server menanganinya / menelan itu, maka tidak akan ada kesempatan untuk memberi tahu klien bahwa kesalahan telah terjadi.

Catatan: Untuk memberikan deskripsi yang jelas tentang apa yang telah terjadi jenis kesalahan kita dapat membuat objek Pengecualian kita sendiri dan melemparkannya ke klien.

JAWA
sumber
Poin yang bagus. Maksudnya adalah menggelembungkannya ke lapisan paling bertanggung jawab atas yang mengontrol aliran logika dan mengawasi logika bisnis untuk aplikasi tersebut. Tidak mungkin, misalnya, untuk lapisan database untuk berkomunikasi dengan klien bahwa ada sesuatu yang kritis yang hilang atau tidak responsif. Ketika gelembung naik ke lapisan server paling atas maka itu lurus ke depan untuk menyegarkan pandangan klien dengan pesan kesalahan kritis.
Salvador Valencia
3

Saya pikir pengecualian yang diperiksa adalah pengingat yang baik untuk pengembang yang menggunakan perpustakaan eksternal bahwa ada yang salah dengan kode dari perpustakaan itu dalam situasi luar biasa.

Baca lebih lanjut tentang pengecualian dicentang vs tidak dicentang di sini http://learnjava.today/2015/11/checked-vs-unchecked-exceptions/

Dan Moldovan
sumber
3

Saya hanya ingin menambahkan beberapa alasan untuk tidak menggunakan pengecualian yang diperiksa sama sekali. Ini bukan jawaban yang lengkap, tetapi saya merasa itu menjawab sebagian dari pertanyaan Anda, dan melengkapi banyak jawaban lainnya.

Setiap kali pengecualian yang diperiksa terlibat, ada suatu throws CheckedExceptiontempat di dalam tanda tangan metode ( CheckedExceptionbisa berupa pengecualian yang diperiksa). Tanda tangan TIDAK melemparkan Pengecualian, melemparkan Pengecualian adalah aspek implementasi. Antarmuka, tanda tangan metode, kelas induk, semua hal ini TIDAK harus bergantung pada implementasinya. Penggunaan Pengecualian yang dicentang di sini (sebenarnya fakta bahwa Anda harus mendeklarasikan throwsdalam tanda tangan metode) mengikat antarmuka tingkat tinggi Anda dengan implementasi antarmuka ini.

Mari saya tunjukkan sebuah contoh.

Mari kita memiliki antarmuka yang bagus dan bersih seperti ini

public interface IFoo {
    public void foo();
}

Sekarang kita dapat menulis banyak implementasi metode foo(), seperti ini

public class Foo implements IFoo {
    @Override
    public void foo() {
        System.out.println("I don't throw and exception");
    }
}

Kelas Foo baik-baik saja. Sekarang mari kita membuat upaya pertama di kelas Bar

public class Bar implements IFoo {
    @Override
    public void foo() {
        //I'm using InterruptedExcepton because you probably heard about it somewhere. It's a checked exception. Any checked exception will work the same.
        throw new InterruptedException();
    }
}

Bar kelas ini tidak akan dikompilasi. Karena InterruptedException adalah pengecualian yang dicentang, Anda harus menangkapnya (dengan try-catch inside method foo ()) atau menyatakan bahwa Anda membuangnya (menambah throws InterruptedExceptiontanda tangan metode). Karena saya tidak ingin menangkap pengecualian ini di sini (saya ingin itu menyebar ke atas sehingga saya bisa menghadapinya dengan benar di tempat lain), mari kita ubah tanda tangan.

public class Bar implements IFoo {
    @Override
    public void foo() throws InterruptedException {
        throw new InterruptedException();
    }
}

Bar kelas ini tidak akan dikompilasi juga! Metode bar foo () TIDAK menimpa metode IFoo foo () karena tanda tangannya berbeda. Saya bisa menghapus anotasi @Override, tapi saya ingin memprogram terhadap antarmuka IFoo suka IFoo foo;dan nanti memutuskan implementasi yang ingin saya gunakan, seperti foo = new Bar();. Jika metode foo Bar () tidak menggantikan metode foo IFoo, ketika saya melakukannya foo.foo();tidak akan memanggil implementasi foo () Bar.

Untuk membuat Bar public void foo() throws InterruptedExceptionmenimpa IFoo, public void foo()saya HARUS menambahkan throws InterruptedExceptionke tanda tangan metode IFoo. Akan tetapi, ini akan menyebabkan masalah dengan kelas Foo saya, karena tanda tangan metode foo () berbeda dari tanda tangan metode IFoo. Selain itu, jika saya menambahkan throws InterruptedExceptionke metode Foo foo () saya akan mendapatkan kesalahan lain yang menyatakan bahwa metode Foo foo () menyatakan bahwa ia melempar InterruptedException namun tidak pernah melempar InterruptedException.

Seperti yang Anda lihat (jika saya melakukan pekerjaan yang layak dalam menjelaskan hal ini), fakta bahwa saya melempar pengecualian yang diperiksa seperti InterruptedException memaksa saya untuk mengikat antarmuka IFoo ke salah satu implementasinya, yang pada gilirannya menyebabkan kekacauan pada IFoo implementasi lainnya!

Ini adalah salah satu alasan utama mengapa pengecualian yang diperiksa adalah BURUK. Dalam topi.

Salah satu solusinya adalah menangkap pengecualian yang dicentang, membungkusnya dalam pengecualian yang tidak dicentang, dan membuang pengecualian yang tidak dicentang.

Blueriver
sumber
2
Ya, itu buruk karena kamu bilang kamu tidak ingin menangkapnya. Tetapi untuk mencegah memengaruhi tanda tangan IFOO, Anda harus melakukannya. Saya lebih suka melakukan itu dan beralih daripada menyeimbangkan kembali semua tanda tangan antarmuka saya untuk menghindari penangkapan pengecualian (hanya karena pengecualiannya buruk).
Salvador Valencia
Ya saya setuju. Saya agak tidak jelas tentang sesuatu. Saya ingin perkecualian untuk menyebar, sehingga saya bisa menghadapinya di tempat lain. Salah satu solusinya adalah menangkap InterruptedException dan melempar pengecualian yang tidak dicentang. yaitu kita menghindari pengecualian yang dicentang dan memberikan pengecualian yang tidak dicentang (meskipun hanya masuk akal sebagai pembungkus)
Blueriver
"Akan tetapi, ini akan menyebabkan masalah dengan kelas Foo saya, karena tanda tangan metode foo () berbeda dari tanda tangan metode IFoo". Saya baru saja menguji ide Anda, dan dimungkinkan untuk mengkompilasi bahkan jika kita menambah throws InterruptedExceptionmetode tanda tangan IFoo tanpa membuang apa pun dalam implementasi apa pun. Jadi itu tidak benar-benar menyebabkan masalah. Jika dalam sebuah antarmuka Anda membuat setiap metode tanda tangan lempar Exception, itu hanya memberikan implementasi pilihan untuk melempar atau tidak membuang pengecualian (pengecualian apa pun, seperti Exceptionmerangkum semua pengecualian).
Flyout91
Namun saya akui itu bisa membingungkan karena ketika Anda akan mengimplementasikan inteface seperti itu dan mengklik sesuatu seperti "Tambahkan metode yang tidak diimplementasikan", mereka akan secara otomatis dibuat dengan throw Exceptionklausa dalam tanda tangan mereka, meskipun implementasi Anda tidak akan membuang apa pun atau mungkin pengecualian yang lebih spesifik. Tapi saya masih merasa itu adalah praktik yang baik untuk selalu membuang Exception untuk metode Interface karena, sekali lagi, ini memberikan pengguna pilihan untuk melempar atau tidak melempar apa pun.
Flyout91
Ini melewatkan seluruh poin. Tujuan dari antarmuka adalah untuk menyatakan kontrak yang harus dipenuhi oleh klien. Ini dapat mencakup skenario kegagalan yang dapat ditangani. Ketika implementasi menemukan kesalahan, itu harus memetakan kesalahan itu ke kegagalan abstrak yang sesuai yang dinyatakan oleh antarmuka klien.
erickson
3
  • Java membedakan antara dua kategori pengecualian (dicentang & tidak dicentang).
  • Java memberlakukan tangkapan atau persyaratan yang dinyatakan untuk pengecualian yang diperiksa.
  • Jenis pengecualian menentukan apakah pengecualian dicentang atau tidak dicentang.
  • Semua tipe pengecualian yang langsung atau tidak langsung subclassesdari kelas RuntimeException adalah pengecualian yang tidak dicentang.
  • Semua kelas yang mewarisi dari kelas Exceptiontetapi tidak RuntimeExceptiondianggap checked exceptions.
  • Kelas yang mewarisi dari kesalahan kelas dianggap tidak dicentang.
  • Compiler memeriksa setiap pemanggilan metode dan perlambatan untuk menentukan apakah metode melempar checked exception.
    • Jika demikian kompiler memastikan pengecualian ditangkap atau dinyatakan dalam klausa pelemparan.
  • Untuk memenuhi bagian menyatakan persyaratan catch-atau-menyatakan, metode yang menghasilkan pengecualian harus menyediakan throwsklausa yang berisi checked-exception.
  • Exception kelas didefinisikan untuk diperiksa ketika mereka dianggap cukup penting untuk ditangkap atau dideklarasikan.
tokhi
sumber
2

Berikut adalah aturan sederhana yang dapat membantu Anda memutuskan. Ini terkait dengan bagaimana antarmuka digunakan di Jawa.

Ambil kelas Anda dan bayangkan merancang antarmuka untuk itu sehingga antarmuka menggambarkan fungsionalitas kelas tetapi tidak ada implementasi yang mendasarinya (sebagaimana seharusnya antarmuka). Berpura-puralah mungkin Anda dapat mengimplementasikan kelas dengan cara lain.

Lihatlah metode antarmuka dan pertimbangkan pengecualian yang mungkin mereka keluarkan:

Jika pengecualian dapat dilemparkan oleh suatu metode, terlepas dari implementasi yang mendasarinya (dengan kata lain, itu menggambarkan fungsionalitas saja) maka itu mungkin harus menjadi pengecualian yang diperiksa di antarmuka.

Jika pengecualian disebabkan oleh implementasi yang mendasarinya, seharusnya tidak ada di antarmuka. Oleh karena itu, itu harus berupa pengecualian yang tidak dicentang di kelas Anda (karena pengecualian yang tidak dicentang tidak perlu muncul dalam tanda tangan antarmuka), atau Anda harus membungkusnya dan menyusun kembali sebagai pengecualian yang diperiksa yang merupakan bagian dari metode antarmuka.

Untuk memutuskan apakah Anda harus membungkus dan rethrow, Anda harus mempertimbangkan lagi apakah masuk akal bagi pengguna antarmuka untuk segera menangani kondisi pengecualian, atau pengecualian yang begitu umum sehingga tidak ada yang dapat Anda lakukan tentang hal itu dan harus menyebarkan tumpukan. Apakah pengecualian yang dibungkus masuk akal ketika dinyatakan sebagai fungsionalitas dari antarmuka baru yang Anda tetapkan atau apakah itu hanya pembawa untuk sekumpulan kondisi kesalahan yang mungkin yang juga dapat terjadi pada metode lain? Jika yang pertama, itu mungkin masih merupakan pengecualian yang diperiksa, jika tidak maka harus tidak dicentang.

Anda biasanya tidak boleh merencanakan untuk "melambungkan" pengecualian (catch and rethrow). Entah pengecualian harus ditangani oleh penelepon (dalam hal ini dicek) atau harus naik sepenuhnya ke penangan tingkat tinggi (dalam hal ini paling mudah jika tidak dicentang).

rghome
sumber
2

Hanya untuk menunjukkan bahwa jika Anda melempar pengecualian yang dicentang ke dalam kode dan tangkapannya beberapa tingkat di atas, Anda perlu mendeklarasikan pengecualian dalam tanda tangan setiap metode antara Anda dan tangkapan. Jadi, enkapsulasi rusak karena semua fungsi di jalur lempar harus tahu tentang detail pengecualian itu.

Zoran Pandovski
sumber
2

Singkatnya, pengecualian yang harus ditangani oleh modul atau modul Anda selama runtime disebut pengecualian yang diperiksa; lain pengecualian dicentang yang baik RuntimeExceptionatau Error.

Dalam video ini, ini menjelaskan pengecualian dicentang dan tidak dicentang di Jawa:
https://www.youtube.com/watch?v=ue2pOqLaArw

Ozgen
sumber
1

Semua itu diperiksa pengecualian. Pengecualian yang tidak dicentang adalah subclass dari RuntimeException. Keputusannya bukan bagaimana menanganinya, itu harus kode Anda membuangnya. Jika Anda tidak ingin kompiler memberi tahu Anda bahwa Anda belum menangani pengecualian, maka Anda menggunakan pengecualian (subkelas RuntimeException) yang tidak dicentang. Itu harus disimpan untuk situasi yang tidak dapat Anda pulihkan, seperti kehabisan memori kesalahan dan sejenisnya.

mamboking
sumber
um jika NumberFormatException adalah pengecualian yang diperiksa, seperti yang Anda katakan, bukankah itu bertentangan dengan fakta bahwa itu diwarisi dari RuntimeException ?
eis
Maaf, saya tidak begitu jelas. Saya merujuk pada FileNotFoundException bukan NumberFormatException. Berdasarkan # 2 & # 4-nya, sepertinya dia berpikir bahwa Checked vs Unchecked didasarkan pada bagaimana Anda menangani pengecualian setelah menangkapnya. Bukan bagaimana itu didefinisikan.
mamboking
-1

Jika ada yang peduli dengan bukti lain untuk tidak menyukai pengecualian yang diperiksa, lihat beberapa paragraf pertama dari perpustakaan JSON yang populer:

"Meskipun ini merupakan pengecualian yang dicentang, ini jarang dapat dipulihkan. Sebagian besar penelepon hanya harus membungkus pengecualian ini dalam pengecualian yang tidak dicentang dan rethrow:"

Jadi mengapa ada orang yang membuat pengembang terus memeriksa pengecualian, jika kita harus "membungkusnya" saja? lol

http://developer.android.com/reference/org/json/JSONException.html

Slawomir
sumber
4
Karena hanya sebagian besar penelepon, tidak semua penelepon, yang harus membungkus dan memikirkan kembali. Fakta bahwa pengecualian dicentang berarti penelepon harus memikirkan apakah mereka adalah salah satu penelepon "paling", atau salah satu dari minoritas yang dapat dan harus menangani pengecualian.
Warren Dew
1
Jika Anda suka memeriksa kesalahan untuk setiap panggilan yang Anda lakukan, "kembali" ke C. Pengecualian adalah cara untuk memisahkan eksekusi program normal dari abnormal, tanpa mencemari kode Anda. Pengecualian memastikan Anda tidak dapat mengabaikan kesalahan secara diam-diam pada tingkat tertentu .
Slawomir
-1

Pengecualian yang Diperiksa :

  • Pengecualian yang diperiksa oleh kompiler untuk kelancaran pelaksanaan program saat runtime disebut Pengecualian yang Diperiksa.

  • Ini terjadi pada waktu kompilasi.

  • Jika ini tidak ditangani dengan benar, mereka akan memberikan kesalahan waktu kompilasi (Bukan Pengecualian).
  • Semua subclass kelas Exception kecuali RuntimeException adalah Checked Exception.

    Contoh Hipotetis - Misalkan Anda meninggalkan rumah untuk ujian, tetapi jika Anda memeriksa apakah Anda mengambil Tiket Hall di rumah (waktu kompilasi) maka tidak akan ada masalah di Ruang Ujian (runtime).

Pengecualian tidak dicentang :

  • Pengecualian yang tidak diperiksa oleh kompiler disebut Pengecualian Tidak Dicentang.

  • Ini terjadi saat runtime.

  • Jika pengecualian ini tidak ditangani dengan benar, mereka tidak memberikan kesalahan waktu kompilasi. Tetapi program ini akan dihentikan sebelum waktunya pada saat runtime.

  • Semua subclass dari RunTimeException dan Kesalahan adalah pengecualian yang tidak dicentang.

    Contoh Hipotetis - Misalkan Anda berada di ruang ujian tetapi entah bagaimana sekolah Anda mengalami kecelakaan kebakaran (berarti saat runtime) di mana Anda tidak dapat melakukan apa pun pada waktu itu tetapi tindakan pencegahan dapat dilakukan sebelumnya (waktu kompilasi).

Varun Vashista
sumber
-2

Semua pengecualian harus diperiksa pengecualian.

  1. Pengecualian yang tidak dicentang adalah goto yang tidak dibatasi. Dan goto yang tidak terbatas dianggap sebagai hal yang buruk.

  2. Pengecualian yang tidak dicentang merusak enkapsulasi. Untuk memprosesnya dengan benar, semua fungsi di pohon panggilan antara pelempar dan penangkap harus diketahui untuk menghindari bug.

  3. Pengecualian adalah kesalahan dalam fungsi yang melemparnya tetapi bukan kesalahan dalam fungsi yang memprosesnya. Tujuan pengecualian adalah untuk memberikan program kesempatan kedua dengan menunda keputusan apakah itu kesalahan atau tidak untuk konteks lain. Hanya dalam konteks lain keputusan yang tepat dapat dibuat.

shawnhcorey
sumber