Java.lang.Error ne zaman yakalanır?


Yanıtlar:


101

Genellikle, asla.

Ancak, bazen belirli hataları yakalamanız gerekir.

Framework-ish kod yazıyorsanız (3. taraf sınıfları yüklüyorsanız), yakalamak akıllıca olabilir LinkageError(sınıf bulunamadı, tatmin edici olmayan bağlantı, uyumsuz sınıf değişikliği).

Ayrıca alt sınıfları atan bazı aptal üçüncü taraf kodlar da gördüm Error, bu yüzden bunları da halletmeniz gerekecek.

Bu arada, iyileşmenin mümkün olmadığından emin değilim OutOfMemoryError.


3
DLL'leri tam olarak yüklemek için yapmam gerektiğini, doğru yapılandırılmadıkları takdirde bu başarısız olur. Bu uygulama durumunda ölümcül bir hata değildir.
Mario Ortegón

7
Bazen, örneğin büyük dizi listeleri oluştururken OutOfMemoryError'ı yakalamak mantıklı olabilir.
SpaceTrucker

3
@SpaceTrucker: Bu yaklaşım çok iş parçacıklı uygulamalarda iyi çalışıyor mu, yoksa bu nedenle diğer iş parçacıklarındaki daha küçük ayırmaların başarısız olma riski var mı? ... muhtemelen sadece dizileriniz tahsis edilebilecek kadar küçükse, ancak başkası için hiçbir şey bırakmıyorsa.
PJTraill

@PJTraill Bundan emin değilim. Bu, bazı gerçek dünya istatistiksel örneklerini gerektirecektir. Böyle bir kod gördüğümü sanıyordum ama nerede olduğunu hatırlayamıyorum.
SpaceTrucker

51

Asla. Uygulamanın sonraki kod satırını çalıştırabileceğinden asla emin olamazsınız. Eğer bir alırsanız OutOfMemoryError, her şeyi güvenilir bir şekilde yapabileceğinizi garanti edemezsiniz . RuntimeException'ı yakalayın ve İstisnaları işaretleyin, ancak Hatalar'ı asla kontrol etmedi.

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


27
Asla asla Deme. "yanlış olduğunu iddia eden" test kodumuz var; daha sonra -ea bayrağının ayarlandığından emin olmak için AssertionError'ı yakalar. Bunun dışında ... evet, muhtemelen asla ;-)
Outlaw Programmer

3
İstekleri çalışan iş parçacıklarına teslim eden bir sunucu uygulamasına ne dersiniz? Herhangi bir hatayı yakalamak için çalışan iş parçacığı üzerinde Throwable'ı yakalamak ve en azından neyin yanlış gittiğini kaydetmeye çalışmak mantıklı olmaz mı?
Leigh

11
Asla ... kesinlikle ihtiyacın olduğu durumlar dışında. Asla güçlü bir kelime değildir ve her zaman kuralların istisnaları vardır. Bir çerçeve oluşturuyorsanız, yalnızca günlüğe kaydetmek için bile olsa, belirli hataları yakalamanız ve işlemeniz pek olası değildir.
Robin

Hatalar, örneğin üçüncü taraf kitaplık yöntemlerinden gelen NoSuchMethodError nasıl olur?
ha9u63ar

@OutlawProgrammer Sadece kayıt için, aynı testi yapmanın başka yolları da var:boolean assertionsEnabled = false; assert assertionsEnabled = true;
shmosel

16

Genellikle, her zaman yakalayıp java.lang.Errorbir günlüğe yazmalı veya kullanıcıya göstermelisiniz. Destek olarak çalışıyorum ve her gün programcıların bir programda ne olduğunu söyleyemediklerini görüyorum.

Bir daemon iş parçacığınız varsa, sonlandırılmasını önlemelisiniz. Diğer durumlarda uygulamanız düzgün çalışacaktır.

Sadece java.lang.Erroren yüksek seviyede yakalamalısın .

Hataların listesine bakarsanız, çoğunun ele alınabileceğini göreceksiniz. Örneğin ZipError, bozuk zip dosyalarını okurken bir meydana gelir.

En yaygın hatalar OutOfMemoryErrorve NoClassDefFoundErrorçoğu durumda her ikisi de çalışma zamanı sorunlarıdır.

Örneğin:

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

bir üretebilir, OutOfMemoryErrorancak bu bir çalışma zamanı problemidir ve programınızı sonlandırmanız için bir neden yoktur.

NoClassDefFoundErrorçoğunlukla bir kitaplık yoksa veya başka bir Java sürümüyle çalışıyorsanız oluşur. Programınızın isteğe bağlı bir parçasıysa, programınızı sonlandırmamalısınız.

ThrowableEn üst seviyede yakalamanın ve yardımcı bir hata mesajı üretmenin neden iyi bir fikir olduğuna dair daha birçok örnek verebilirim .


Bu durumlarda, arka plan programını uygun uyarılarla başarısızlığa uğratmanın, ardından da gerçekten canlı olduğu ve bir şeyler yaptığı gibi yanlış bir bahane verebileceği başarısız bir jvm'de bir etik hayalet olarak hayatta kalma olasılığına sahip olmasının daha iyi olduğundan şüpheleniyorum
Andrew Norman

OutOfMemoryErrorbir çalışma zamanı hatası değildir, uygulamanın bundan kurtulabileceğinin garantisi yoktur. Şanslıysanız, OOM alabilirsiniz, new byte[largeNumber]ancak bu tahsis OOM'ye neden olmak için yeterli değilse, sonraki satırda veya sonraki iş parçacığında tetiklenebilir. Bu çalışma zamanı sorunudur, çünkü lengthgüvenilir olmayan bir girdi ise , çağrı yapmadan önce doğrulanması gerekir new byte[].
Jeeyoung Kim

NoClassDefFoundErroroluşabilir yerde derlenmiş java kodu bir sınıf bulamadıkları zaman o çağrılır olarak. JDK'nız yanlış yapılandırılmışsa, java.util.*sınıfı kullanmaya çalışmaktan tetiklenebilir ve ona karşı programlamak pratik olarak imkansızdır. İsteğe bağlı olarak bir bağımlılık ekliyorsanız, ClassLoadervar olup olmadığını kontrol etmek için kullanmalısınız , bu da fırlatır ClassNotFoundException.
Jeeyoung Kim

1
ZipErrorsınıfları içeren jar dosyasının bozuk bir zip dosyası olduğunu belirtir. Bu oldukça ciddi bir sorundur ve bu noktada çalıştırılan herhangi bir koda güvenemezsiniz ve ondan "kurtarmaya" çalışmak sorumsuzca bir şey olur.
Jeeyoung Kim

2
Genel olarak, yakalamak java.lang.Errorveya java.lang.Throwableen üst düzeyde yapmak ve onunla bir şeyler yapmaya çalışmak faydalı olabilir - diyelim ki bir hata mesajı kaydedin. Ancak bu noktada bunun yerine getirileceğine dair bir garanti yok. JVM'niz StringOOM yapıyorsa, günlüğe kaydetmeye çalışmak başka bir OOM'yi tetikleyen daha fazla s tahsis edebilir .
Jeeyoung Kim

15

Çok iş parçacıklı bir ortamda, çoğu zaman onu yakalamak istersiniz! Yakaladığınızda, günlüğe kaydedin ve tüm uygulamayı sonlandırın! Bunu yapmazsanız, önemli bir kısmını yapan bazı iş parçacıkları ölür ve uygulamanın geri kalanı her şeyin normal olduğunu düşünür. Bunun dışında birçok istenmeyen durum ortaya çıkabilir. En küçük sorunlardan biri, bir iş parçacığının çalışmaması nedeniyle diğer iş parçacıkları bazı istisnalar atmaya başlarsa, sorunun kökenini kolayca bulamayacağınızdır.

Örneğin, genellikle döngü şöyle olmalıdır:

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

Bazı durumlarda bile, farklı Hataları farklı şekilde ele almak isteyebilirsiniz, örneğin, OutOfMemoryError'da uygulamayı düzenli olarak kapatabilirsiniz (hatta bir miktar hafızayı boşaltabilir ve devam edebilirsiniz), bazılarında ise yapabileceğiniz pek bir şey yoktur.


1
Anında var olmak yerine yakalamak OutOfMemoryError ve devam etmek akıllıca değildir , çünkü programınız o zaman tanımlanmamış bir durumdadır .
Raedwald

1
çağrı sistemi, fırlatılabilir bir cihazı yakalamadan çıkıldığında, yalnızca söz konusu uygulamayı değil, JVM'de çalışan her şeyi öldürmek gibi istenmeyen bir sonuç vardır. Diğer web uygulamalarıyla birlikte bir uygulama sunucusunda barındırılabilen web uygulamaları için genellikle iyi bir uygulama değildir (uygulama sunucusunun kendisini de etkileyeceğini belirtmiyorum).
Andrew Norman

9

Çok nadiren.

Bir iş parçacığının ölme nedeni ile bir mesaj yayınlamaya ATTEMPT için yalnızca bir iş parçacığının en üst düzeyinde söyleyebilirim.

Bu tür şeyleri sizin için yapan bir çerçevedeyseniz, çerçeveye bırakın.


6

Neredeyse hiç. Hatalar, uygulamaların genellikle hiçbir şey yapamadığı sorunlar olarak tasarlanmıştır. Tek istisna, hatanın sunumunu ele almak olabilir, ancak bu bile hataya bağlı olarak planlandığı gibi gitmeyebilir.


6

Bir Errorgenellikle yakalanmış olmamalı o kadar, hiçbir zaman ortaya anormal bir duruma işaret eder .

ErrorSınıf için Java API Spesifikasyonundan :

An Error, Throwable makul bir uygulamanın yakalamaya çalışmaması gereken ciddi sorunları gösteren bir alt sınıfıdır . Bu tür hataların çoğu anormal durumlardır. [...]

Bir yöntemin, yöntemin yürütülmesi sırasında atılan ancak yakalanmayan herhangi bir Error alt sınıfını kendi throws cümlesinde bildirmesi gerekmez, çünkü bu hatalar asla oluşmaması gereken anormal koşullardır.

Spesifikasyonda belirtildiği gibi, bir Erroryalnızca Şansların olduğu durumlarda atılır, bir Errormeydana geldiğinde uygulamanın yapabileceği çok az şey vardır ve bazı durumlarda Java Sanal Makinesi kararsız bir durumda olabilir (örneğin VirtualMachineError)

ErrorBir alt sınıfı olmasına rağmen , bir cümle Throwabletarafından yakalanabileceği anlamına gelir try-catch, ancak ErrorJVM tarafından bir atıldığında uygulama anormal bir durumda olacağından muhtemelen gerçekten gerekli değildir .

Bölümde bu konuda kısa bir bölüm de var 11.5 İstisna Hiyerarşi içinde Java Dili Şartname, 2. Baskı .


6

Yeni bir birim test çerçevesi oluşturacak kadar çılgınsanız, test koşucunuzun muhtemelen herhangi bir test durumu tarafından fırlatılan java.lang.AssertionError dosyasını yakalamaya ihtiyacı olacaktır.

Aksi takdirde, diğer cevaplara bakın.


5

Ve bir Hata alırsanız , onu yeniden atmanız gereken birkaç durum daha vardır . Örneğin, ThreadDeath asla yakalanmamalıdır, büyük bir soruna neden olabilir, eğer onu kapalı bir ortamda yakalarsanız (örneğin bir uygulama sunucusu):

Bir uygulama, bu sınıfın örneklerini ancak zaman uyumsuz olarak sonlandırıldıktan sonra temizlemesi gerekiyorsa yakalamalıdır. ThreadDeath bir yöntem tarafından yakalanırsa, iş parçacığının gerçekten ölmesi için yeniden atılması önemlidir.


2
Sadece çünkü hangi aslında olmayan bir konudur değil yakalamak Errors.
Bombe

4

Çok çok nadiren.

Bunu sadece çok özel bilinen bir vaka için yaptım. Örneğin, iki bağımsız ClassLoader aynı DLL dosyasını yüklüyse java.lang.UnsatisfiedLinkError atılabilir . (JAR'ı paylaşılan bir sınıf yükleyiciye taşımam gerektiğini kabul ediyorum)

Ancak en yaygın durum, kullanıcı şikayet etmeye geldiğinde ne olduğunu öğrenmek için oturum açmanız gerektiğidir. Sessizce ölmek yerine kullanıcıya bir mesaj veya açılır pencere istiyorsun.

C / C ++ programcıları bile, bir hatayı ortaya çıkarırlar ve çıkmadan önce insanların anlamadıkları bir şeyi söylerler (örneğin, hafıza hatası).


3

Bir Android uygulamasında bir java.lang.VerifyError yakalıyorum . Kullandığım bir kitaplık, işletim sisteminin eski sürümüne sahip cihazlarda çalışmaz ve kitaplık kodu böyle bir hata verir. İşletim zamanında işletim sistemi sürümünü kontrol ederek hatayı elbette önleyebilirim, ancak:

  • Desteklenen en eski SDK, belirli kitaplık için gelecekte değişebilir
  • Try-catch hata bloğu, daha büyük bir geri düşme mekanizmasının parçasıdır. Bazı özel cihazlar, kitaplığı desteklemeleri gerekse de istisnalar atarlar. Geri dönüş çözümü kullanmak için VerifyError ve tüm İstisnaları yakaladım.

3

java.lang.AssertionError'ı test ortamında yakalamak oldukça kullanışlıdır ...


Hangi değeri katmaya çalışıyorsun?
lpapp

iptal edilmeyen bir test paketinin değerini eklemek
Jono

2

İdeal olarak hataları işlememeli / yakalamamalıyız. Ancak çerçevenin veya uygulamanın gerekliliğine bağlı olarak yapmamız gereken durumlar olabilir. Daha fazla Bellek tüketen DOM Ayrıştırıcıyı uygulayan bir XML Ayrıştırıcı arka plan programım olduğunu varsayalım . Ayrıştırıcı iş parçacığı gibi bir gereksinim varsa OutOfMemoryError aldığında ölmemeli , bunun yerine onu ele almalı ve uygulama / çerçeve yöneticisine bir mesaj / posta göndermelidir.


1

ideal olarak Java uygulamamızda anormal bir durum olduğu için Hatayı asla yakalamamalıyız. Uygulama anormal durumda olacak ve araba takılmasına veya ciddi şekilde yanlış sonuçlara neden olabilir.


1

Bir iddianın yapıldığını kontrol eden birim testlerinde hata yakalamak uygun olabilir. Birisi iddiaları devre dışı bırakırsa veya başka bir şekilde silmek isterse bilmek isteyeceğiniz iddiayı


1

JVM artık beklendiği gibi çalışmadığında veya eşiğinde olduğunda bir Hata var. Bir hata yakalarsanız, catch bloğunun çalışacağının ve sonuna kadar çalışacağının garantisi yoktur.

Aynı zamanda çalışan bilgisayara, mevcut bellek durumuna da bağlı olacaktır, bu nedenle test etmenin, denemenin ve elinizden gelenin en iyisini yapmanın bir yolu yoktur. Sadece kötü bir sonuca sahip olacaksınız.

Ayrıca kodunuzun okunabilirliğini de düşüreceksiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.