Kapan menangkap java.lang.Error?

Jawaban:

101

Umumnya tidak pernah.

Namun, terkadang Anda perlu menangkap kesalahan tertentu.

Jika Anda menulis kode framework-ish (memuat kelas pihak ketiga), mungkin bijaksana untuk menangkapnya LinkageError(tidak ditemukan kelas def, link tidak puas, perubahan kelas tidak kompatibel).

Saya juga telah melihat beberapa kode pihak ketiga yang bodoh melempar subkelas Error, jadi Anda harus menanganinya juga.

Ngomong-ngomong, saya tidak yakin itu tidak mungkin pulih OutOfMemoryError.

Yoni Roit
sumber
3
Yang harus saya lakukan dengan tepat untuk memuat DLL, yang akan gagal jika tidak dikonfigurasi dengan benar. Bukan kesalahan fatal dalam kasus aplikasi ini.
Mario Ortegón
7
Terkadang masuk akal untuk menangkap OutOfMemoryError - misalnya saat Anda membuat daftar array yang besar.
SpaceTrucker
3
@ SpaceTrucker: apakah pendekatan itu berfungsi dengan baik di aplikasi multithread, atau apakah ada risiko signifikan bahwa alokasi yang lebih kecil di thread lain gagal karena itu? … Mungkin hanya jika array Anda hanya cukup kecil untuk dialokasikan, tetapi tidak menyisakan apa pun untuk orang lain.
PJTraill
@PJTraill Saya tidak yakin tentang itu. Ini akan membutuhkan beberapa sampel statistik dunia nyata. Saya pikir saya telah melihat kode seperti itu, tetapi tidak dapat mengingat di mana itu.
SpaceTrucker
51

Tidak pernah. Anda tidak pernah bisa yakin bahwa aplikasi dapat mengeksekusi baris kode berikutnya. Jika Anda mendapatkan OutOfMemoryError, Anda tidak memiliki jaminan bahwa Anda akan dapat melakukan apa pun dengan andal . Tangkap RuntimeException dan periksa Pengecualian, tetapi jangan pernah Kesalahan.

http://pmd.sourceforge.net/rules/strictexception.html

tronda
sumber
27
Jangan pernah bilang tidak akan pernah. kami memiliki kode pengujian yang melakukan "assert false;" kemudian menangkap AssertionError untuk memastikan bahwa flag -ea disetel. Selain itu ... ya, mungkin tidak pernah ;-)
Outlaw Programmer
3
Bagaimana dengan aplikasi server yang menyerahkan permintaan ke utas pekerja. Mungkinkah tidak masuk akal untuk menangkap Throwable di thread pekerja untuk menjebak kesalahan apa pun, dan setidaknya mencoba mencatat apa yang salah?
Leigh
11
Tidak pernah ... kecuali jika Anda benar-benar perlu. Tidak pernah ada kata yang kuat dan selalu ada pengecualian pada aturan. Jika Anda membangun kerangka kerja, bukan berarti Anda harus menangkap dan menangani kesalahan tertentu, bahkan jika itu hanya untuk log.
Robin
Bagaimana dengan kesalahan misalnya NoSuchMethodError yang berasal dari metode perpustakaan pihak ketiga?
ha9u63ar
@OutlawProgrammer Hanya sebagai catatan, ada cara lain untuk melakukan tes yang sama:boolean assertionsEnabled = false; assert assertionsEnabled = true;
shmosel
16

Umumnya Anda harus selalu menangkap java.lang.Errordan menulisnya ke log atau menampilkannya kepada pengguna. Saya bekerja sebagai pendukung dan melihat setiap hari bahwa programmer tidak dapat mengetahui apa yang telah terjadi dalam suatu program.

Jika Anda memiliki utas daemon maka Anda harus mencegahnya dihentikan. Dalam kasus lain, aplikasi Anda akan berfungsi dengan benar.

Anda seharusnya hanya menangkap java.lang.Errordi level tertinggi.

Jika Anda melihat daftar kesalahan, Anda akan melihat bahwa sebagian besar kesalahan dapat ditangani. Misalnya ZipErrorterjadi saat membaca file zip yang rusak.

Kesalahan paling umum adalah OutOfMemoryErrordan NoClassDefFoundError, yang dalam banyak kasus merupakan masalah runtime.

Sebagai contoh:

int length = Integer.parseInt(xyz);
byte[] buffer = new byte[length];

dapat menghasilkan OutOfMemoryErrortetapi ini adalah masalah runtime dan tidak ada alasan untuk menghentikan program Anda.

NoClassDefFoundErrorterjadi terutama jika perpustakaan tidak ada atau jika Anda bekerja dengan versi Java lain. Jika ini adalah bagian opsional dari program Anda, maka Anda tidak boleh menghentikan program Anda.

Saya dapat memberikan lebih banyak contoh mengapa merupakan ide yang baik untuk menangkap Throwabledi tingkat atas dan menghasilkan pesan kesalahan yang berguna.

Horcrux7
sumber
Saya akan curiga lebih baik dalam kasus-kasus itu untuk gagal daemon dengan peringatan yang tepat kemudian memiliki kemungkinan itu tetap hidup sebagai hantu eterial pada jvm yang gagal di mana itu mungkin memberikan alasan palsu bahwa itu benar-benar hidup dan melakukan sesuatu
Andrew Norman
OutOfMemoryErrorBukan error runtime, tidak ada jaminan bahwa aplikasi dapat memulihkannya. Jika Anda beruntung, Anda mungkin mendapatkan OOM new byte[largeNumber]tetapi jika alokasi itu tidak cukup untuk menyebabkan OOM, ini dapat dipicu di baris berikutnya atau utas berikutnya. Ini adalah masalah waktu proses karena jika lengthinput tidak tepercaya, itu harus divalidasi sebelum dipanggil new byte[].
Jeeyoung Kim
NoClassDefFoundErrordapat terjadi di mana saja , karena dipanggil ketika kode java yang dikompilasi tidak dapat menemukan kelas. Jika JDK Anda salah dikonfigurasi, JDK dapat memicu dari mencoba menggunakan java.util.*kelas dan secara praktis tidak mungkin untuk memprogramnya. Jika Anda secara opsional menyertakan dependensi, Anda harus menggunakan ClassLoaderuntuk memeriksa apakah ada, yang melempar ClassNotFoundException.
Jeeyoung Kim
1
ZipErrormenunjukkan bahwa file jar yang berisi kelas adalah file zip yang rusak. Ini adalah masalah yang cukup serius dan pada titik ini Anda tidak dapat mempercayai kode apa pun yang dieksekusi dan akan menjadi hal yang tidak bertanggung jawab untuk mencoba "memulihkan" darinya.
Jeeyoung Kim
2
Secara umum, mungkin berguna untuk menangkap java.lang.Erroratau java.lang.Throwabledi tingkat atas dan mencoba melakukan sesuatu dengannya - katakan catat pesan kesalahan. Tetapi pada saat itu tidak ada jaminan bahwa ini akan dilaksanakan. Jika JVM Anda OOM, mencoba untuk mencatat mungkin mengalokasikan lebih banyak Stringyang memicu OOM lain.
Jeeyoung Kim
15

Dalam lingkungan multithread, Anda paling sering ingin menangkapnya! Saat Anda menangkapnya, catat, dan hentikan seluruh aplikasi! Jika Anda tidak melakukannya, beberapa utas yang mungkin melakukan beberapa bagian penting akan mati, dan sisa aplikasi akan berpikir bahwa semuanya normal. Dari situ, banyak situasi yang tidak diinginkan bisa terjadi. Satu masalah terkecil adalah Anda tidak akan dapat dengan mudah menemukan akar masalah, jika utas lain mulai mengeluarkan beberapa pengecualian karena satu utas tidak berfungsi.

Misalnya, biasanya loop harus:

try {
   while (shouldRun()) {
       doSomething();
   }
}
catch (Throwable t) {
   log(t);
   stop();
   System.exit(1);
}

Bahkan dalam beberapa kasus, Anda ingin menangani Kesalahan yang berbeda secara berbeda, misalnya, pada OutOfMemoryError Anda dapat menutup aplikasi secara teratur (bahkan mungkin membebaskan beberapa memori, dan melanjutkan), pada beberapa lainnya, tidak banyak yang dapat Anda lakukan.

Sarmun
sumber
1
Menangkap OutOfMemoryError dan melanjutkan daripada langsung saat itu tidak bijaksana karena program Anda kemudian dalam status tidak ditentukan .
Raedwald
1
memanggil sistem, keluar saat menangkap throwable memiliki konsekuensi yang tidak diinginkan yaitu mematikan semua yang berjalan di JVM dan bukan hanya aplikasi yang dipermasalahkan. Biasanya bukan praktik yang baik untuk aplikasi web yang mungkin dihosting di server aplikasi dengan aplikasi web lain (belum lagi hal itu akan memengaruhi server aplikasi itu sendiri).
Andrew Norman
9

Sangat jarang.

Saya akan mengatakan hanya di tingkat atas utas untuk MENCOBA untuk mengeluarkan pesan dengan alasan utas sekarat.

Jika Anda berada dalam kerangka kerja yang melakukan hal semacam ini untuk Anda, serahkan pada kerangka kerja.

Darron
sumber
6

Hampir tidak pernah. Kesalahan dirancang untuk menjadi masalah yang umumnya tidak dapat dilakukan oleh aplikasi. Satu-satunya pengecualian mungkin untuk menangani presentasi kesalahan tetapi bahkan itu mungkin tidak berjalan sesuai rencana tergantung pada kesalahannya.

nicerobot
sumber
6

Sebuah Errorbiasanya tidak harus dapat ditangkap , karena menunjukkan kondisi normal yang seharusnya tidak terjadi .

Dari Spesifikasi Java API untuk Errorkelas:

An Erroradalah subclass dari Throwable yang menunjukkan masalah serius yang seharusnya tidak ditangkap oleh aplikasi yang wajar. Sebagian besar kesalahan tersebut adalah kondisi abnormal. [...]

Sebuah metode tidak diharuskan untuk mendeklarasikan dalam klausa lemparannya setiap subkelas Kesalahan yang mungkin terlempar selama pelaksanaan metode tetapi tidak tertangkap, karena kesalahan ini adalah kondisi abnormal yang seharusnya tidak pernah terjadi.

Seperti yang disebutkan dalam spesifikasi, an Errorhanya dilemparkan dalam keadaan yang Kemungkinannya, ketika Errorterjadi, sangat sedikit yang dapat dilakukan aplikasi, dan dalam beberapa keadaan, Java Virtual Machine sendiri mungkin dalam keadaan tidak stabil (seperti VirtualMachineError)

Meskipun an Erroradalah subclass Throwableyang artinya dapat ditangkap oleh try-catchklausa, tetapi mungkin tidak terlalu diperlukan, karena aplikasi akan berada dalam status tidak normal saat Errordilempar oleh JVM.

Ada juga bagian pendek tentang topik ini dalam Bagian 11.5 Eksepsi Hirarki dari Jawa Bahasa Spesifikasi, 2nd Edition .

burung coobird
sumber
6

Jika Anda cukup gila untuk membuat framework pengujian unit baru, runner pengujian Anda mungkin perlu menangkap java.lang.AssertionError yang dilemparkan oleh kasus pengujian apa pun.

Jika tidak, lihat jawaban lain.

noahlz
sumber
5

Dan ada beberapa kasus lain di mana jika Anda menemukan Kesalahan, Anda harus mengembalikannya . Misalnya ThreadDeath tidak boleh tertangkap, ini dapat menyebabkan masalah besar jika Anda menangkapnya di lingkungan yang terkandung (misalnya server aplikasi):

Aplikasi harus menangkap instance dari kelas ini hanya jika harus dibersihkan setelah dihentikan secara asinkron. Jika ThreadDeath tertangkap oleh suatu metode, penting untuk mencabutnya kembali sehingga utas benar-benar mati.

Guillaume
sumber
2
Yang sebenarnya bukan masalah karena Anda tidak menangkap Errors.
Bombe
4

Sangat, sangat jarang.

Saya melakukannya hanya untuk satu kasus yang diketahui sangat spesifik. Misalnya, java.lang.UnsatisfiedLinkError bisa dilempar jika dua ClassLoader independen memuat DLL yang sama. (Saya setuju bahwa saya harus memindahkan JAR ke classloader bersama)

Tetapi kasus yang paling umum adalah Anda membutuhkan logging untuk mengetahui apa yang terjadi ketika pengguna datang untuk mengeluh. Anda ingin pesan atau popup ke pengguna, daripada mati diam-diam.

Bahkan programmer di C / C ++, mereka memunculkan kesalahan dan memberitahu sesuatu yang tidak dimengerti orang sebelum keluar (misalnya kegagalan memori).

Dennis C
sumber
3

Dalam aplikasi Android saya menangkap java.lang.VerifyError . Perpustakaan yang saya gunakan tidak akan berfungsi di perangkat dengan versi OS lama dan kode perpustakaan akan menimbulkan kesalahan seperti itu. Saya tentu saja dapat menghindari kesalahan dengan memeriksa versi OS saat runtime, tetapi:

  • SDK terlama yang didukung dapat berubah di masa mendatang untuk pustaka tertentu
  • Blok kesalahan coba-tangkap adalah bagian dari mekanisme mundur yang lebih besar. Beberapa perangkat tertentu, meskipun seharusnya mendukung pustaka, mengeluarkan pengecualian. Saya menangkap VerifyError dan semua Pengecualian untuk menggunakan solusi mundur.
kgiannakakis
sumber
3

cukup berguna untuk menangkap java.lang.AssertionError di lingkungan pengujian ...

Jono
sumber
Nilai apa yang Anda coba tambahkan?
lpapp
menambahkan nilai rangkaian pengujian yang tidak membatalkan
Jono
2

Idealnya kami tidak menangani / menangkap kesalahan. Tetapi mungkin ada kasus di mana kita perlu melakukannya, berdasarkan persyaratan kerangka kerja atau aplikasi. Katakanlah saya memiliki daemon XML Parser yang mengimplementasikan DOM Parser yang menghabiskan lebih banyak Memori. Jika ada persyaratan seperti untaian Parser tidak boleh mati ketika mendapat OutOfMemoryError , melainkan harus menanganinya dan mengirim pesan / email ke administrator aplikasi / kerangka kerja.

pengguna3510364
sumber
1

idealnya kita tidak boleh menangkap Error dalam aplikasi Java kita karena ini adalah kondisi yang tidak normal. Aplikasi akan berada dalam keadaan tidak normal dan dapat mengakibatkan mobil atau memberikan hasil yang sangat salah.

Vivek
sumber
1

Mungkin tepat untuk menangkap kesalahan dalam pengujian unit yang memeriksa pernyataan dibuat. Jika seseorang menonaktifkan pernyataan atau menghapus pernyataan yang ingin Anda ketahui

Chanoch
sumber
1

Ada kesalahan saat JVM tidak lagi berfungsi seperti yang diharapkan, atau hampir. Jika Anda menemukan kesalahan, tidak ada jaminan bahwa blok penangkap akan berjalan, dan bahkan lebih sedikit lagi yang akan berjalan sampai akhir.

Ini juga akan tergantung pada komputer yang sedang berjalan, status memori saat ini, jadi tidak ada cara untuk menguji, mencoba dan melakukan yang terbaik. Anda hanya akan mendapatkan hasil yang sulit.

Anda juga akan menurunkan keterbacaan kode Anda.

Nicolas Zozol
sumber