Yakalamak kötü bir uygulama Throwable
mı?
Ö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 Throwable
mı?
Ö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, Throwable
kapaklar Error
da 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 Exception
genellikle 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 ThreadDeath
Hata 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/catch
tü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 List
ve 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);
}
}
throwable
Gerç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
, struts2
ve 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 Throwable
sorun olur Throwable
mu" 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 Throwable
ya IOException
da 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, Throwable
bir 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, Error
ancak (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 Throwable
yararlı 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-catch
bloğa yerleştirilir Throwable
ve akışın geri kalanının devam etmesine izin verir.
Exception
, ama değil Throwable
.