mencoba / menangkap versus melempar Pengecualian

117

Apakah pernyataan kode ini setara? Apakah ada perbedaan di antara keduanya?

private void calculateArea() throws Exception {
    ....do something
}

private void calculateArea() {
    try {
        ....do something
    } catch (Exception e) {
        showException(e);
    }
}
carlos
sumber
3
Bukan jawaban yang sebenarnya, tetapi Anda mungkin tertarik dengan artikel Ned Batchelder, Pengecualian di Hutan Hujan , yang membantu menjelaskan kasus umum di mana satu gaya atau lainnya lebih disukai.
Daniel Pryden
1
Alih-alih memiliki "showException (e)" di tangkapan, apakah Anda bertanya apakah Anda malah "melempar e" di tangkapan (atau tidak mencoba / menangkap sama sekali)?
MacGyver

Jawaban:

146

Ya, ada perbedaan besar - yang terakhir menelan pengecualian (menunjukkannya, memang), sedangkan yang pertama akan membiarkannya menyebar. (Saya berasumsi bahwa showExceptionitu tidak mengulanginya.)

Jadi jika Anda memanggil metode pertama dan "melakukan sesuatu" gagal, pemanggil harus menangani pengecualian. Jika Anda memanggil metode kedua dan "melakukan sesuatu" gagal, maka pemanggil tidak akan melihat pengecualian sama sekali ... yang umumnya merupakan hal yang buruk, kecuali showExceptiontelah benar-benar menangani pengecualian tersebut, memperbaiki apa pun yang salah, dan secara umum memastikan yang calculateAreatelah mencapai tujuannya.

Anda akan dapat mengatakan ini, karena Anda tidak dapat memanggil metode pertama tanpa baik menangkap Exceptionsendiri atau menyatakan bahwa metode Anda mungkin membuangnya juga.

Jon Skeet
sumber
12
Ketika Anda menyebutkan bahwa "Kecuali itu benar-benar menangani pengecualian", itu poin yang bagus. Saya hanya berpikir saya akan menambahkan bahwa menangkap "Exception" itu sendiri jarang mengarah pada "penanganan" yang cerdas dari pengecualian aktual yang merupakan alasan orang merekomendasikan Anda untuk menangkap pengecualian yang paling spesifik.
Bill K
17
+1. Karena Jon Skeet membutuhkan lebih banyak reputasi. Oh, dan jawabannya juga bagus.
Jonathan Spiller
20

Yang pertama throws Exception, jadi penelepon harus menangani Exception. Yang kedua menangkap dan menangani secara Exceptioninternal, sehingga pemanggil tidak perlu melakukan penanganan pengecualian apa pun.

samitgaur
sumber
Jadi secara singkat, saya harus selalu menggunakan yang kedua. Apakah saya benar? Yang pertama sebenarnya adalah metode yang digunakan di berbagai titik program. Itu sebabnya saya memutuskan untuk mengumpulkan bersama-sama petunjuk untuk digunakan lebih lanjut tetapi setelah melakukannya saya sekarang menyadari bahwa T membuat kesalahan besar ..
carlos
9
Tidak, kedua pola itu dibutuhkan. Jika metode Anda dapat menangani pengecualian, gunakan pola kedua, jika tidak, gunakan pola pertama untuk memberi tahu pemanggil.
Andreas Dolk
Versi mana yang Anda gunakan bergantung pada kebutuhan Anda - pada dasarnya pada tingkat apa Anda perlu menangani pengecualian itu. Penelepon perlu diberi kode yang sesuai. Jika pemanggil memanggil versi pertama, dan Anda mengganti definisi metode dengan versi kedua, kode pemanggil Anda akan dipaksa untuk menangani pengecualian karena ini adalah pengecualian yang dicentang.
samitgaur
16

Iya. Versi yang mendeklarasikan throws Exceptionakan membutuhkan kode panggilan untuk menangani pengecualian, sedangkan versi yang secara eksplisit menanganinya tidak akan.

yaitu, secara sederhana:

performCalculation();

vs. memindahkan beban penanganan pengecualian ke pemanggil:

try {
    performCalculation();
catch (Exception e) {
    // handle exception
}
Lyle
sumber
6

Ya, ada banyak sekali perbedaan di antara keduanya. Di blok kode pertama, Anda meneruskan pengecualian ke kode panggilan. Di blok kode kedua Anda menanganinya sendiri. Metode mana yang benar bergantung sepenuhnya pada apa yang Anda lakukan. Dalam beberapa kasus, Anda ingin kode Anda menangani pengecualian (jika file tidak ditemukan dan Anda ingin membuatnya, misalnya) tetapi dalam kasus lain, Anda ingin kode panggilan menangani pengecualian (file tidak ditemukan dan mereka perlu menentukan yang baru atau membuatnya).

Secara umum juga, Anda tidak ingin menangkap pengecualian umum. Alih-alih, Anda hanya ingin menangkap yang spesifik, seperti FileNotFoundExceptionatau IOExceptionkarena itu dapat memiliki arti yang berbeda.

Chris Thompson
sumber
3

Ada satu skenario tertentu di mana kita tidak bisa menggunakan lemparan, kita harus menggunakan coba-tangkap. Ada aturan "Metode yang diganti tidak dapat menampilkan pengecualian tambahan apa pun selain yang dilontarkan oleh kelas induknya". Jika ada pengecualian ekstra yang harus ditangani menggunakan coba-tangkap. Pertimbangkan cuplikan kode ini. Ada kelas dasar yang sederhana

package trycatchvsthrows;

public class Base {
    public void show()
    {
        System.out.println("hello from base");
    }
}

dan kelas turunannya:

package trycatchvsthrows;

public class Derived extends Base {

    @Override
    public void show()   {
        // TODO Auto-generated method stub
        super.show();

        Thread thread= new Thread();
        thread.start();
        try {
            thread.sleep(100);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        // thread.sleep(10);
        // here we can not use public void show() throws InterruptedException 
        // not allowed
    }
}

Ketika kita harus memanggil thread.sleep () kita terpaksa menggunakan try-catch, disini kita tidak bisa menggunakan:

 public void show() throws InterruptedException

karena metode yang diganti tidak dapat mengeluarkan pengecualian ekstra.

Arjun Thakur
sumber
Saya yakin tidak semua orang mengetahui peringatan ini. Runcing.
ivanleoncz
1

Saya berasumsi bahwa dengan "identik" Anda mengacu pada perilaku.

Perilaku suatu fungsi dapat ditentukan oleh:

1) Nilai yang dikembalikan

2) Dilempar pengecualian

3) Efek samping (yaitu perubahan pada heap, sistem file, dll.)

Dalam kasus ini, metode pertama menyebarkan pengecualian apa pun, sedangkan metode kedua tidak melontarkan pengecualian yang dicentang, dan menelan sebagian besar pengecualian yang tidak dicentang juga, sehingga perilakunya berbeda.

Namun, jika Anda menjamin bahwa "melakukan sesuatu" tidak pernah memunculkan pengecualian, maka perilakunya akan sama (meskipun kompilator akan meminta pemanggil untuk menangani pengecualian tersebut, pada versi pertama)

--edit--

Dari sudut pandang desain API, metodenya sangat berbeda dalam kontraknya. Selain itu, melempar Exception kelas tidak disarankan. Coba lemparkan sesuatu yang lebih spesifik untuk memungkinkan penelepon menangani pengecualian dengan lebih baik.

Eyal Schneider
sumber
1

Jika Anda melontarkan pengecualian, metode anak (yang menimpa ini) harus menangani pengecualian tersebut

contoh:

class A{
public void myMethod() throws Exception{
 //do something
}
}

A a=new A();
try{
a.myMethod();
}catch Exception(e){
//handle the exception
}
Sherif Eldeeb
sumber
0

Sering kali Anda ingin penelepon menangani pengecualian. Misalkan Anda meminta pemanggil memanggil metode yang memanggil metode lain yang memanggil metode lain, alih-alih meminta setiap metode menangani pengecualian, Anda bisa menanganinya di pemanggil. Kecuali, Anda ingin melakukan sesuatu di salah satu metode ketika metode itu gagal.

isaace
sumber
0

Pemanggil metode ini perlu menangkap pengecualian ini atau mendeklarasikannya untuk dicabut kembali dalam tanda tangan metode itu.

private void calculateArea() throws Exception {
    // Do something
}

Dalam contoh blok coba-tangkap di bawah ini. Pemanggil metode ini tidak perlu khawatir tentang menangani pengecualian karena sudah ditangani.

private void calculateArea() {
    try {
        // Do something

    } catch (Exception e) {
        showException(e);
    }
}
JSON C11
sumber
0
private void calculateArea() throws Exception {
    ....do something
}

Ini melempar pengecualian, jadi pemanggil bertanggung jawab untuk menangani pengecualian itu tetapi jika pemanggil tidak menangani pengecualian tersebut maka mungkin itu akan diberikan ke jvm yang dapat mengakibatkan penghentian program yang tidak normal.

Sedangkan pada kasus kedua:

private void calculateArea() {
    try {
        ....do something
    } catch (Exception e) {
        showException(e);
    }
}

Di sini pengecualian ditangani oleh callee, jadi tidak ada kemungkinan penghentian program yang tidak normal.

Coba tangkap adalah pendekatan yang direkomendasikan.

IMO,

  • Melempar kata kunci yang paling sering digunakan dengan pengecualian Diperiksa untuk meyakinkan compiler tetapi tidak menjamin penghentian program secara normal.

  • Melempar kata kunci mendelegasikan tanggung jawab penanganan pengecualian ke
    pemanggil (JVM atau metode lain).

  • Kata kunci lemparan diperlukan untuk pengecualian yang dicentang saja, untuk pengecualian yang tidak dicentang tidak ada penggunaan kata kunci lemparan.

Nitin Pawar
sumber