답변:
가능한 한 구체적이어야합니다. 그렇지 않으면 예상치 못한 버그가 이런 식으로 사라질 수 있습니다.
게다가, Throwable
커버 Error
도 마찬가지이며 일반적으로 반환 지점이 아닙니다 . 당신은 그것을 잡거나 다루고 싶지 않고, 당신은 당신의 프로그램이 즉시 죽어 올바르게 고칠 수 있기를 원합니다.
이것은 나쁜 생각입니다. 사실, 잡는 Exception
것 조차도 일반적으로 나쁜 생각입니다. 예를 들어 보겠습니다.
try {
inputNumber = NumberFormat.getInstance().formatNumber( getUserInput() );
} catch(Throwable e) {
inputNumber = 10; //Default, user did not enter valid number
}
이제 getUserInput ()이 잠시 차단되고 다른 스레드가 최악의 방법으로 스레드를 중지한다고 가정 해 보겠습니다 (thread.stop () 호출). catch 블록은 ThreadDeath
오류 를 포착합니다 . 이것은 매우 나쁩니다. 해당 예외를 포착 한 후 코드의 동작은 거의 정의되지 않았습니다.
예외를 잡는 것과 비슷한 문제가 발생합니다. 아마도getUserInput()
때문에 InterruptException의 실패, 또는 결과, 또는 다른 실패의 모든 종류를 기록하는 동안 권한은 예외를 부인했다. 그 때문에 문제를 해결하는 방법도 모르기 때문에 무엇이 잘못되었는지 전혀 모릅니다.
세 가지 더 나은 옵션이 있습니다.
1-처리 방법을 알고있는 예외를 정확히 포착합니다.
try {
inputNumber = NumberFormat.getInstance().formatNumber( getUserInput() );
} catch(ParseException e) {
inputNumber = 10; //Default, user did not enter valid number
}
2-발생하고 처리 방법을 모르는 예외를 다시 발생시킵니다.
try {
doSomethingMysterious();
} catch(Exception e) {
log.error("Oh man, something bad and mysterious happened",e);
throw e;
}
3-finally 블록을 사용하면 다시 던지는 것을 기억할 필요가 없습니다.
Resources r = null;
try {
r = allocateSomeResources();
doSomething(r);
} finally {
if(r!=null) cleanUpResources(r);
}
throw new Exception("Some additional info, eg. userId " + userId, e);
입니다. 이것은 10 가지 원인과 함께 하나의 멋진 예외에 기록됩니다.
또한을 잡을 때 특별한 치료가 필요한 Throwable
잡을 수도 있습니다 InterruptedException
. 자세한 내용 은 InterruptedException 처리 를 참조하십시오.
확인되지 않은 예외 만 포착하려는 경우이 패턴을 고려할 수도 있습니다.
try {
...
} catch (RuntimeException exception) {
//do something
} catch (Error error) {
//do something
}
이렇게하면 코드를 수정하고 확인 된 예외를 throw 할 수있는 메서드 호출을 추가 할 때 컴파일러가이를 상기시켜주고이 경우에 수행 할 작업을 결정할 수 있습니다.
Error 클래스의 javadoc에서 직접 가져온 것입니다 (잡지 않는 것이 좋습니다).
* 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
메서드에서 예외 버블을 절대로 가질 수 없다면 나쁜 습관이 아닙니다.
정말 예외를 처리 할 수 없다면 나쁜 습관입니다. 단순히 catch하고 다시 던지는 것보다 메소드 서명에 "throws"를 추가하는 것이 더 좋으며, 더 나쁜 것은 RuntimeException에 래핑하고 다시 던지는 것입니다.
Throwable
인스턴스 를 처리하는 데 절대적으로 합법적 인 경우가 있습니다 ( 예 : 사용자 정의 예외 로깅).
오류를 지나치게 많이 던지는 라이브러리를 사용하는 경우 Throwable 잡기가 필요할 때가 있습니다. 그렇지 않으면 라이브러리가 애플리케이션을 종료 할 수 있습니다.
그러나 이러한 상황에서는 모든 Throwables가 아니라 라이브러리에서 발생한 특정 오류 만 지정하는 것이 가장 좋습니다.
Throwable은 throw 될 수있는 모든 클래스의 기본 클래스입니다 (예외뿐만 아니라). OutOfMemoryError 또는 KernelError를 포착하면 할 수있는 일이 거의 없습니다 ( java.lang.Error 를 포착하는 경우 참조 )
예외를 잡는 것으로 충분합니다.
매우 나쁜 습관으로 설명되지만 때때로 드물게 발견 될 수 있습니다. 되지만 유용 할뿐만 아니라 필수 인 경우도 있습니다. 다음은 두 가지 예입니다.
사용자에게 의미있는 전체 오류 페이지를 표시해야하는 웹 애플리케이션에서. 이 코드는 try/catch
모든 요청 처리기 (서블릿, struts 작업 또는 모든 컨트롤러 ....) 주변 에서 큰 문제가 발생하는지 확인합니다 .
try{
//run the code which handles user request.
}catch(Throwable ex){
LOG.error("Exception was thrown: {}", ex);
//redirect request to a error page.
}
}
또 다른 예로, 자금 이체 비즈니스에 서비스를 제공하는 서비스 클래스가 있다고 가정하십시오. 이 메서드는 TransferReceipt
전송이 완료되었거나 NULL
불가능한 경우를 반환합니다 .
String FoundtransferService.doTransfer( fundtransferVO);
이제 이미징 List
은 사용자로부터 자금 이체를 받고 위의 서비스를 사용하여 모든 작업을 수행해야합니다.
for(FundTransferVO fundTransferVO : fundTransferVOList){
FoundtransferService.doTransfer( foundtransferVO);
}
하지만 무슨 일이 일어날 어떤 예외가됩니까? 한 번의 전송이 성공하고 다른 하나는 성공하지 않았을 수 있으므로 중단해서는 안됩니다. 모든 사용자를 계속 진행 List
하고 각 전송에 결과를 표시해야합니다. 따라서이 코드로 끝납니다.
for(FundTransferVO fundTransferVO : fundTransferVOList){
FoundtransferService.doTransfer( foundtransferVO);
}catch(Throwable ex){
LOG.error("The transfer for {} failed due the error {}", foundtransferVO, ex);
}
}
많은 오픈 소스 프로젝트를 탐색하여 throwable
실제로 캐시되고 처리되는지 확인할 수 있습니다. 예를 들어 여기의 검색이며 tomcat
, struts2
그리고 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
.
질문은 약간 모호합니다. " Throwable
잡아도 Throwable
됩니까"아니면 " 잡아도 아무 것도하지 않아도 괜찮 습니까?"라고 물으십니까? 여기에있는 많은 사람들이 후자에 대해 대답했지만 그것은 부수적 인 문제입니다. 당신이 잡고있다 여부를 시간의 99 %는 당신이해야하지, "소비"또는 예외를 폐기 Throwable
하거나 IOException
또는 무엇 이건.
예외를 전파하면 많은 질문에 대한 대답과 같은 대답은 "상황에 따라 다름"입니다. 예외를 제외하고 수행하는 작업에 따라 다릅니다.이를 포착하는 이유는 무엇입니까?
잡으려 Throwable
는 이유에 대한 좋은 예는 오류가있는 경우 일종의 정리를 제공하는 것입니다. 예를 들어 JDBC에서 트랜잭션 중에 오류가 발생하면 트랜잭션을 롤백 할 수 있습니다.
try {
…
} catch(final Throwable throwable) {
connection.rollback();
throw throwable;
}
예외는 삭제되지 않고 전파됩니다.
그러나 일반적인 정책으로, Throwable
이유가없고 어떤 특정 예외가 발생하는지 알기에는 너무 게으 르기 때문에 잡는 것은 잘못된 형식이며 나쁜 생각입니다.
일반적으로 Error
s를 잡는 것을 피하고 싶지만 그렇게하는 것이 적절한 경우 (적어도) 두 가지 특정 경우를 생각할 수 있습니다.
AssertionError
무해한 오류에 대한 응답으로 애플리케이션을 종료하려고합니다 .throwable 을 사용하면 Error 도 다룹니다 .
예.
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();
}
}
산출:
java.lang.ArithmeticException: / by zero
at com.infy.test.ExceptionTest.m1(ExceptionTest.java:12)
at com.infy.test.ExceptionTest.main(ExceptionTest.java:25)
Throwable은 모든 오류와 예외의 슈퍼 클래스입니다. catch 절에서 Throwable을 사용하면 모든 예외를 포착 할뿐만 아니라 모든 오류도 포착합니다. JVM은 애플리케이션에서 처리 할 수없는 심각한 문제를 나타 내기 위해 오류를 발생시킵니다. 이에 대한 일반적인 예는 OutOfMemoryError 또는 StackOverflowError입니다. 둘 다 응용 프로그램의 제어를 벗어난 상황으로 인해 발생하며 처리 할 수 없습니다. 따라서 Throwable 내부에있는 예외 일 뿐이라는 확신이 없으면 Throwables를 잡아서는 안됩니다.
Throwable을 잡는 것은 일반적으로 나쁜 습관이지만 (이 질문에 대한 수많은 답변에 의해 설명 된 바와 같이), 잡는 시나리오는 Throwable
가 유용한 는 매우 일반적입니다. 제가 직장에서 사용하는 사례 중 하나를 간단한 예를 들어 설명하겠습니다.
두 개의 숫자를 더하는 방법을 고려하고 성공적으로 더한 후 특정 사람들에게 이메일 알림을 보냅니다. 반환 된 숫자가 중요하고 호출 메서드에서 사용한다고 가정합니다.
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
}
}
이메일 경고를 보내는 코드는 많은 시스템 구성을 읽으므로 해당 코드 블록에서 다양한 예외가 발생할 수 있습니다. 그러나 경고 전달 중에 발생한 예외가 호출자 메서드로 전파되는 것을 원하지 않습니다. 해당 메서드는 단순히 제공하는 두 정수 값의 합계와 관련이 있기 때문입니다. 따라서 이메일 경고를 발송하는 코드는 try-catch
블록에 배치되며 , 여기서 Throwable
잡히고 예외는 로깅 만되어 나머지 흐름이 계속됩니다.
Exception
s를 잡아라 Throwable
. 그러나 .