Yakalamak kötü bir uygulama Throwablemı?
Örneğin bunun gibi bir şey:
try {
// Some code
} catch(Throwable e) {
// handle the exception
}
Bu kötü bir uygulama mı yoksa mümkün olduğunca spesifik olmalıyız?
Yakalamak kötü bir uygulama Throwablemı?
Örneğin bunun gibi bir şey:
try {
// Some code
} catch(Throwable e) {
// handle the exception
}
Bu kötü bir uygulama mı yoksa mümkün olduğunca spesifik olmalıyız?
Yanıtlar:
Mümkün olduğunca spesifik olmanız gerekir. Aksi takdirde öngörülemeyen böcekler bu şekilde uzaklaşabilir.
Ayrıca, Throwablekapaklar Errorda ve bu genellikle geri dönüş noktası değildir . Bunu yakalamak / halletmek istemezsiniz, programınızın derhal ölmesini istersiniz, böylece onu düzgün bir şekilde düzeltebilirsiniz.
Bu kötü bir fikir. Aslında, yakalamak bile Exceptiongenellikle kötü bir fikirdir. Bir örnek ele alalım:
try {
inputNumber = NumberFormat.getInstance().formatNumber( getUserInput() );
} catch(Throwable e) {
inputNumber = 10; //Default, user did not enter valid number
}
Şimdi, getUserInput () işlevinin bir süre engellendiğini ve başka bir iş parçacığının iş parçacığınızı mümkün olan en kötü şekilde durdurduğunu varsayalım (thread.stop () çağırır). Yakalama bloğunuz bir ThreadDeathHata yakalayacaktır . Bu çok kötü. Bu İstisnayı yakaladıktan sonra kodunuzun davranışı büyük ölçüde tanımsızdır.
İstisna yakalanırken de benzer bir sorun oluşur. Belki getUserInput()bir InterruptException nedeniyle başarısız olabilir veya sonuçları günlüğe kaydetmeye çalışırken bir izin reddedilen istisna veya her türlü başka hata olabilir. Neyin yanlış gittiğine dair hiçbir fikriniz yok, çünkü bu yüzden sorunu nasıl çözeceğiniz konusunda da hiçbir fikriniz yok.
Üç daha iyi seçeneğiniz var:
1 - Nasıl işleneceğini bildiğiniz İstisnaları tam olarak yakalayın:
try {
inputNumber = NumberFormat.getInstance().formatNumber( getUserInput() );
} catch(ParseException e) {
inputNumber = 10; //Default, user did not enter valid number
}
2 - Karşılaştığınız istisnaları yeniden atın ve nasıl başa çıkacağınızı bilmiyorsanız:
try {
doSomethingMysterious();
} catch(Exception e) {
log.error("Oh man, something bad and mysterious happened",e);
throw e;
}
3 - Son olarak bir blok kullanın, böylece yeniden atmayı hatırlamak zorunda kalmazsınız:
Resources r = null;
try {
r = allocateSomeResources();
doSomething(r);
} finally {
if(r!=null) cleanUpResources(r);
}
throw new Exception("Some additional info, eg. userId " + userId, e);. Bu, 10 nedenden oluşan güzel bir istisna ile kaydedilir.
Ayrıca Throwable, yakaladığınız zaman , InterruptedExceptionözel bir tedavi gerektiren bir şeyi yakalayabileceğinizi de unutmayın . Daha fazla ayrıntı için InterruptedException ile Başa Çıkma konusuna bakın .
Yalnızca kontrol edilmeyen istisnaları yakalamak istiyorsanız, bu modeli de düşünebilirsiniz.
try {
...
} catch (RuntimeException exception) {
//do something
} catch (Error error) {
//do something
}
Bu şekilde, kodunuzu değiştirdiğinizde ve kontrol edilen bir istisna atabilecek bir yöntem çağrısı eklediğinizde, derleyici size bunu hatırlatır ve bu durumda ne yapacağınıza karar verebilirsiniz.
doğrudan Error sınıfının javadoc'undan (bunların yakalanmamasını önerir):
* An <code>Error</code> is a subclass of <code>Throwable</code>
* that indicates serious problems that a reasonable application
* should not try to catch. Most such errors are abnormal conditions.
* The <code>ThreadDeath</code> error, though a "normal" condition,
* is also a subclass of <code>Error</code> because most applications
* should not try to catch it.
* A method is not required to declare in its <code>throws</code>
* clause any subclasses of <code>Error</code> that might be thrown
* during the execution of the method but not caught, since these
* errors are abnormal conditions that should never occur.
*
* @author Frank Yellin
* @version %I%, %G%
* @see java.lang.ThreadDeath
* @since JDK1.0
Bir yöntemden kesinlikle bir istisna baloncuğuna sahip olamazsanız, bu kötü bir uygulama değildir.
İstisnayı gerçekten kaldıramazsanız, bu kötü bir uygulamadır. Yöntem imzasına "fırlatmalar" eklemek, sadece yakala ve yeniden fırlatmaktan veya daha kötüsü, onu bir RuntimeException içine sarmak ve yeniden atmaktan daha iyidir.
Throwableörneklerin işlenmesi için kesinlikle yasal durumlar vardır - örneğin özel istisna günlüğü için.
Aşırı hevesle Hata veren kitaplıklar kullanıyorsanız, Throwable'ı yakalamak bazen gereklidir, aksi takdirde kitaplığınız uygulamanızı öldürebilir.
Bununla birlikte, bu koşullar altında en iyisi, tüm Fırlatılabilirler yerine yalnızca kitaplık tarafından atılan belirli hataları belirtmek olacaktır.
Fırlatılabilir, tüm sınıflar için atılabilecek temel sınıftır (yalnızca istisnalar değil). Bir OutOfMemoryError veya KernelError yakalarsanız yapabileceğiniz çok az şey var (bkz. Java.lang.Error ne zaman yakalanır? )
İstisnaları yakalamak yeterli olmalıdır.
mantığınıza bağlıdır veya seçeneklerinize / olasılıklarınıza daha spesifiktir. Anlamlı bir şekilde tepki verebileceğiniz herhangi bir özel istisna varsa, önce onu yakalayıp bunu yapabilirsiniz.
Eğer yoksa ve tüm istisnalar ve hatalar için aynı şeyi yapacağınızdan eminseniz (örneğin bir hata mesajı ile çıkış), atılabilir olanı yakalamak sorun olmaz.
Genellikle ilk vaka geçerlidir ve fırlatılabilir olanı yakalayamazsınız. Ancak yine de yakalamanın iyi çalıştığı birçok durum var.
Çok kötü bir uygulama olarak tanımlansa da, bazen sadece yararlı değil aynı zamanda zorunlu olduğu nadir durumlar da bulabilirsiniz . İşte iki örnek.
Kullanıcıya tam anlamıyla bir hata sayfası göstermeniz gereken bir web uygulamasında. Bu kod, try/catchtüm istek işleyicileriniz (servletler, struts eylemleri veya herhangi bir denetleyici ....) etrafında büyük olduğu için bunun olmasını sağlar.
try{
//run the code which handles user request.
}catch(Throwable ex){
LOG.error("Exception was thrown: {}", ex);
//redirect request to a error page.
}
}
Başka bir örnek olarak, fon transferi işine hizmet eden bir hizmet sınıfınız olduğunu düşünün. Bu yöntem TransferReceipt, transfer yapılırsa veya yapılamazsa bir döndürür NULL.
String FoundtransferService.doTransfer( fundtransferVO);
Şimdi List, kullanıcıdan bir para transferi alıyorsunuz ve hepsini yapmak için yukarıdaki hizmeti kullanmanız gerekiyor.
for(FundTransferVO fundTransferVO : fundTransferVOList){
FoundtransferService.doTransfer( foundtransferVO);
}
Ama herhangi bir istisna olursa ne olacak ? Durmamalısınız, çünkü bir transfer başarılı olmuş olabilir ve biri olmayabilir, tüm kullanıcılar üzerinden devam etmeli Listve her transfer için sonucu göstermelisiniz. Yani bu kodla sonuçlanırsınız.
for(FundTransferVO fundTransferVO : fundTransferVOList){
FoundtransferService.doTransfer( foundtransferVO);
}catch(Throwable ex){
LOG.error("The transfer for {} failed due the error {}", foundtransferVO, ex);
}
}
throwableGerçekten önbelleğe alındığını ve işlendiğini görmek için birçok açık kaynaklı projeye göz atabilirsiniz . Örneğin burada tomcat, struts2ve primefaces:
https://github.com/apache/tomcat/search?utf8=%E2%9C%93&q=catch%28Throwable https://github.com/apache/struts/search?utf8=%E2%9C%93&q=catch % 28Throwable https://github.com/primefaces/primefaces/search?utf8=%E2%9C%93&q=catch%28Throwable
throwable, bu soru da ne hakkında
Soru biraz belirsiz; "Yakalamak Throwablesorun olur Throwablemu" mu , yoksa "a'yı yakalayıp hiçbir şey yapmamak sorun olur mu?" Buradaki birçok kişi ikincisini yanıtladı, ama bu bir yan mesele; Yakalama Throwableya IOExceptionda her neyse , zamanın% 99'u istisnayı "tüketmemeli" veya atmamalısınız .
İstisnayı yayarsanız, cevap (pek çok sorunun cevabı gibi) "duruma göre değişir". Bu istisna dışında ne yaptığınıza, neden yakaladığınıza bağlıdır.
Neden yakalamak isteyeceğinize iyi bir örnek Throwable, herhangi bir hata varsa bir tür temizleme sağlamaktır. Örneğin, JDBC'de, bir işlem sırasında bir hata meydana gelirse, işlemi geri almak isteyebilirsiniz:
try {
…
} catch(final Throwable throwable) {
connection.rollback();
throw throwable;
}
İstisnanın atılmadığını, ancak yayıldığını unutmayın.
Ancak genel bir politika olarak, Throwablebir sebebiniz olmadığı ve hangi özel istisnaların atıldığını göremeyecek kadar tembel olduğunuz için yakalamak kötü bir biçim ve kötü bir fikirdir.
Genel olarak, e-postaları yakalamaktan kaçınmak istersiniz, Errorancak (en azından) bunu yapmanın uygun olduğu iki özel durum düşünebilirim:
AssertionError zararsız olan hatalara yanıt olarak uygulamayı kapatmak istiyorsunuz .Kullandığımız takdirde throwable , o zaman kapsar Hata sıra ve bu kadar.
Misal.
public class ExceptionTest {
/**
* @param args
*/
public static void m1() {
int i = 10;
int j = 0;
try {
int k = i / j;
System.out.println(k);
} catch (Throwable th) {
th.printStackTrace();
}
}
public static void main(String[] args) {
m1();
}
}
Çıktı:
java.lang.ArithmeticException: / by zero
at com.infy.test.ExceptionTest.m1(ExceptionTest.java:12)
at com.infy.test.ExceptionTest.main(ExceptionTest.java:25)
Fırlatılabilir, tüm hataların ve dışlamaların üst sınıfıdır. Throwable'ı bir catch cümlesinde kullanırsanız, yalnızca tüm istisnaları değil, tüm hataları da yakalayacaktır. Bir uygulama tarafından ele alınması amaçlanmayan ciddi sorunları belirtmek için JVM tarafından hatalar atılır. Bunun tipik örnekleri OutOfMemoryError veya StackOverflowError'dır. Her ikisi de uygulamanın kontrolü dışında olan ve ele alınamayan durumlardan kaynaklanır. Bu nedenle, bunun yalnızca Throwable içinde bir istisna olacağından oldukça emin değilseniz, Throwables'ı yakalamamalısınız.
Throwable'ı yakalamak genellikle kötü bir uygulama olsa da (bu soruya verilen sayısız yanıtla açıklandığı üzere), yakalamanın Throwableyararlı olduğu senaryolar oldukça yaygındır. İşimde kullandığım böyle bir durumu basitleştirilmiş bir örnekle açıklayayım.
İki sayının eklenmesini gerçekleştiren bir yöntem düşünün ve başarılı bir şekilde eklendikten sonra, belirli kişilere bir e-posta uyarısı gönderir. Döndürülen sayının önemli olduğunu ve arama yöntemi tarafından kullanıldığını varsayın.
public Integer addNumbers(Integer a, Integer b) {
Integer c = a + b; //This will throw a NullPointerException if either
//a or b are set to a null value by the
//calling method
successfulAdditionAlert(c);
return c;
}
private void successfulAdditionAlert(Integer c) {
try {
//Code here to read configurations and send email alerts.
} catch (Throwable e) {
//Code to log any exception that occurs during email dispatch
}
}
E-posta uyarıları göndermek için kullanılan kod, birçok sistem yapılandırmasını okur ve bu nedenle, bu kod bloğundan atılan çeşitli istisnalar olabilir. Ancak, uyarı gönderimi sırasında karşılaşılan herhangi bir istisnanın çağıran yönteme yayılmasını istemiyoruz, çünkü bu yöntem yalnızca sağladığı iki Tamsayı değerinin toplamıyla ilgilidir. Bu nedenle, e-posta uyarılarını gönderecek kod , yakalandığı ve istisnaların yalnızca günlüğe kaydedildiği bir try-catchbloğa yerleştirilir Throwableve akışın geri kalanının devam etmesine izin verir.
Exception, ama değil Throwable.