Bisakah saya menangkap beberapa pengecualian Java dalam klausa tangkapan yang sama?

699

Di Jawa, saya ingin melakukan sesuatu seperti ini:

try {
    ...     
} catch (/* code to catch IllegalArgumentException, SecurityException, 
            IllegalAccessException, and NoSuchFieldException at the same time */) {
   someCode();
}

...dari pada:

try {
    ...     
} catch (IllegalArgumentException e) {
    someCode();
} catch (SecurityException e) {
    someCode();
} catch (IllegalAccessException e) {
    someCode();
} catch (NoSuchFieldException e) {
    someCode();
}

Apakah ada cara untuk melakukan ini?

froadie
sumber

Jawaban:

1131

Ini telah dimungkinkan sejak Java 7 . Sintaks untuk blok multi-tangkap adalah:

try { 
  ...
} catch (IOException | SQLException ex) { 
  ...
}

Namun, ingatlah bahwa jika semua pengecualian milik hierarki kelas yang sama, Anda bisa menangkap tipe pengecualian dasar itu.

Perhatikan juga bahwa Anda tidak dapat menangkap ExceptionA dan ExceptionB di blok yang sama jika ExceptionB diwarisi, baik secara langsung maupun tidak langsung, dari ExceptionA. Kompiler akan mengeluh:

Alternatives in a multi-catch statement cannot be related by subclassing
  Alternative ExceptionB is a subclass of alternative ExceptionA
OscarRyz
sumber
81
TT - mengapa mendefinisikan ulang operator bitwise or( |)? Mengapa tidak menggunakan koma, atau operator yang memiliki makna yang lebih mirip, yaitu logical or( ||)?
ArtOfWarfare
11
@ArtOfWarfare Mungkin mereka pikir itu tidak masalah lagi setelah mereka telah membuat sintaks untuk beberapa batasan untuk obat generik.
JimmyB
12
Tanda XOR (I) tidak sama dengan OR (||), A | B berarti A atau B tetapi tidak keduanya A || B berarti A atau B atau keduanya sehingga untuk pengecualian itu adalah exceptionA atau exceptionB tetapi tidak keduanya sekaligus. inilah sebabnya mereka menggunakan XOR bernyanyi sebagai ganti OR dan Anda dapat melihat dengan jelas ketika pengecualian dilemparkan jika Anda memasukkan 2 pengecualian, salah satunya adalah sub jenis yang lain
user1512999
41
@ user1512999 di Java, bitwise XOR adalah ^ (tanda sisipan) dan bitwise OR adalah | (pipa) docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html
Lewis Baumstark
6
Patut disebutkan bahwa jenis pengecualian yang ditangkap dalam blok multi-tangkapan dievaluasi ke induk yang paling banyak diturunkan
yanpas
104

Tidak persis sebelum Java 7 tetapi, saya akan melakukan sesuatu seperti ini:

Java 6 dan sebelumnya

try {
  //.....
} catch (Exception exc) {
  if (exc instanceof IllegalArgumentException || exc instanceof SecurityException || 
     exc instanceof IllegalAccessException || exc instanceof NoSuchFieldException ) {

     someCode();

  } else if (exc instanceof RuntimeException) {
     throw (RuntimeException) exc;     

  } else {
    throw new RuntimeException(exc);
  }

}



Java 7

try {
  //.....
} catch ( IllegalArgumentException | SecurityException |
         IllegalAccessException |NoSuchFieldException exc) {
  someCode();
}
pengguna454322
sumber
11
Perhatikan bahwa contoh Java 6 Anda mematahkan kemampuan kompiler untuk mengetahui apa yang akan dilempar dari mana.
MichaelBlume
2
@MichaelBlume Benar, yang tidak terlalu buruk. Anda selalu bisa mendapatkan pengecualian asli dengan exc.getCause(). Sebagai catatan tambahan, Robert C. Martin (antara lain) merekomendasikan untuk menggunakan pengecualian yang tidak dicentang (kompiler tidak tahu jenis pengecualian apa yang akan dilemparkan dari sana); lihat Bab 7: Penanganan Kesalahan pada bukunya Kode bersih .
user454322
4
Dalam Anda Java 6 misalnya Anda tidak harus rethrowing pengecualian asli bukan menciptakan contoh pengecualian baru, yaitu throw excbukan throw new RuntimeException(exc)?
David DeMar
5
Ini adalah praktik yang sangat buruk, dari perspektif keterbacaan.
Rajesh J Advani
3
Operasi instan sedikit mahal, lebih baik untuk menghindari sebanyak mungkin.
Paramesh Korrakuti
23

Dalam Java 7 Anda dapat mendefinisikan beberapa klausa tangkapan seperti:

catch (IllegalArgumentException | SecurityException e)
{
    ...
}
crusam
sumber
16

Jika ada hierarki pengecualian, Anda bisa menggunakan kelas dasar untuk menangkap semua subkelas pengecualian. Dalam kasus degenerasi Anda dapat menangkap semua pengecualian Java dengan:

try {
   ...
} catch (Exception e) {
   someCode();
}

Dalam kasus yang lebih umum jika RepositoryException adalah kelas dasar dan PathNotFoundException adalah kelas turunan maka:

try {
   ...
} catch (RepositoryException re) {
   someCode();
} catch (Exception e) {
   someCode();
}

Kode di atas akan menangkap RepositoryException dan PathNotFoundException untuk satu jenis penanganan pengecualian dan semua pengecualian lainnya disatukan. Sejak Java 7, sesuai jawaban @ OscarRyz di atas:

try { 
  ...
} catch( IOException | SQLException ex ) { 
  ...
}
Michael Shopsin
sumber
7
Klausa tangkapan BTW ditangani secara berurutan, jadi jika Anda menempatkan kelas pengecualian orangtua sebelum kelas anak maka tidak pernah disebut misalnya: coba {...} catch (Pengecualian e) {someCode (); } catch (RepositoryException re) {// tidak pernah tercapai}
Michael Shopsin
4
Sebenarnya justru karena itu tidak pernah bisa dijangkau, kode seperti itu bahkan tidak dapat dikompilasi.
polygenelubricants
15

Tidak, satu per pelanggan.

Anda dapat menangkap superclass, seperti java.lang.Exception, selama Anda melakukan tindakan yang sama dalam semua kasus.

try {
    // some code
} catch(Exception e) { //All exceptions are caught here as all are inheriting java.lang.Exception
    e.printStackTrace();
}

Tapi itu mungkin bukan praktik terbaik. Anda seharusnya hanya menangkap pengecualian ketika Anda memiliki strategi untuk benar-benar menanganinya - dan logging dan rethrowing bukan "menanganinya". Jika Anda tidak memiliki tindakan korektif, lebih baik menambahkannya ke tanda tangan metode dan membiarkannya menggelembung ke seseorang yang dapat menangani situasi tersebut.

Duffymo
sumber
20
Bisakah saya mengajukan petisi kepada Anda untuk mengulangi bagian tentang penangkapan java.lang.Exception? Saya menyadari bahwa ini adalah contoh, tetapi saya merasa beberapa orang mungkin membaca jawaban ini dan berkata, "oh, oke, saya akan menangkap Exception", ketika itu mungkin bukan yang mereka inginkan (atau seharusnya) lakukan.
Rob Hruska
2
Saya tahu tentang itu, tetapi saya tidak ingin melakukannya ... Oh, well, saya kira saya terjebak dengan 4 tangkapan kemudian, sampai versi Jawa berikutnya ...
froadie
@duffymo: Apa yang salah dengan logging dan rethrowing? Kecuali bahwa itu mengacaukan kode, itu setara dengan tidak menangkapnya, bukan. Terlihat dari perspektif strategi penanganan kesalahan umum. Yang buruk adalah logging dan tidak rethrowing.
Frank Osterfeld
5
Saya tidak mempertimbangkan logging dan rethrowing menangani apa pun. Saya lebih suka membiarkannya meluap kepada seseorang yang dapat melakukan sesuatu yang berarti. Lapisan terakhir di mana pengecualian tidak boleh luput (misalnya pengontrol di aplikasi web) harus menjadi orang yang mencatat kesalahan dalam kasus itu.
duffymo
Apakah saya satu-satunya yang merasa tidak masuk akal bahwa log tidak secara otomatis dibuat untuk saya? Tampaknya kita semua harus menulis pesan logging bodoh yang sama setiap kali beberapa kode mungkin mengeluarkan pengecualian.
ArtOfWarfare
10

Alternatif yang lebih bersih (tetapi kurang bertele-tele, dan mungkin tidak seperti pilihan) untuk jawaban user454322 di Java 6 (yaitu, Android) adalah untuk menangkap semua Exceptiondan melempar kembali RuntimeException. Ini tidak akan berhasil jika Anda berencana untuk menangkap jenis pengecualian lain di atas tumpukan (kecuali Anda juga melemparkannya kembali), tetapi secara efektif akan menangkap semua pengecualian yang dicentang .

Contohnya:

try {
    // CODE THAT THROWS EXCEPTION
} catch (Exception e) {
    if (e instanceof RuntimeException) {
        // this exception was not expected, so re-throw it
        throw e;
    } else {
        // YOUR CODE FOR ALL CHECKED EXCEPTIONS
    } 
}

Yang sedang berkata, untuk verbosity, mungkin lebih baik untuk mengatur boolean atau variabel lain dan berdasarkan itu jalankan beberapa kode setelah blok try-catch.

Oleg Vaskevich
sumber
1
Pendekatan ini mencegah compiler dari menentukan apakah atau tidak "catch block" akan dapat dijangkau.
the_new_mr
3

Di pra-7 bagaimana dengan:

  Boolean   caught = true;
  Exception e;
  try {
     ...
     caught = false;
  } catch (TransformerException te) {
     e = te;
  } catch (SocketException se) {
     e = se;
  } catch (IOException ie) {
     e = ie;
  }
  if (caught) {
     someCode(); // You can reference Exception e here.
  }
Bill S
sumber
3
wuold menjadi solusi yang bagus. Bagaimana cara memasukkan kontrol akhir caughtdalam sebuah finallyblok?
Andrea_86
Ini membutuhkan lebih banyak baris daripada pertanyaan awal.
Leandro Glossman
1

Iya. Inilah cara menggunakan pemisah pipa (|),

try
{
    .......
}    
catch
{
    catch(IllegalArgumentException | SecurityException | IllegalAccessException | NoSuchFieldException e)
}
Siwa
sumber
Apa gaya kode ini? Tangkapan blok menjadi blok coba?
Sam
1

Untuk kotlin, itu tidak mungkin untuk saat ini tetapi mereka telah mempertimbangkan untuk menambahkannya: Sumber
Tapi untuk saat ini, hanya sedikit trik:

try {
    // code
} catch(ex:Exception) {
    when(ex) {
        is SomeException,
        is AnotherException -> {
            // handle
        }
        else -> throw ex
    }
}
Dr.jacky
sumber
0

Tangkap pengecualian yang kebetulan menjadi kelas induk dalam hierarki pengecualian. Ini tentu saja, praktik buruk . Dalam kasus Anda, pengecualian orang tua yang umum terjadi adalah kelas Pengecualian, dan menangkap setiap pengecualian yang merupakan contoh Pengecualian, memang praktik yang buruk - pengecualian seperti NullPointerException biasanya kesalahan pemrograman dan biasanya harus diselesaikan dengan memeriksa nilai nol.

Vineet Reynolds
sumber