Throwable을 잡는 것은 나쁜 습관인가요?
-
08-09-2020 - |
문제
잡는 것은 나쁜 습관인가? Throwable
?
예를 들어 다음과 같습니다.
try {
// Some code
} catch(Throwable e) {
// handle the exception
}
이것은 나쁜 습관입니까, 아니면 최대한 구체적으로 설명해야 합니까?
해결책
가능한 한 구체적으로 있어야합니다.그렇지 않으면 예기치 않은 버그 가이 방식으로 멀리 떨어질 수 있습니다.
, 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
오류를 잡습니다. 이것은 슈퍼 나쁜 것입니다. 그 예외를 잡은 후 코드의 동작은 크게 정의되지 않습니다.
비슷한 문제가 발생함에 따라 발생합니다. intertartexception 때문에 getUserInput()
가 실패했거나 결과를 기록하려고하는 동안 사용 권한이 거부되었거나 모든 종류의 다른 오류를 기록합니다. 그게 무슨 일이 잘못되었는지 전혀 모르겠다. 그로 인해 문제를 해결하는 방법은 모른다.
세 가지 옵션이 있습니다.
1 - 처리 방법을 알고있는 예외를 정확히 잡으십시오 :
try {
inputNumber = NumberFormat.getInstance().formatNumber( getUserInput() );
} catch(ParseException e) {
inputNumber = 10; //Default, user did not enter valid number
}
.
2 - Rethrow 당신이 실행하고 취급하는 방법을 모르는 예외 :
try {
doSomethingMysterious();
} catch(Exception e) {
log.error("Oh man, something bad and mysterious happened",e);
throw e;
}
.
3 - 마지막으로 블록을 사용하여 Rethrow를 기억할 필요가 없습니다.
Resources r = null;
try {
r = allocateSomeResources();
doSomething(r);
} finally {
if(r!=null) cleanUpResources(r);
}
. 또한 잡을 때 주의하세요. Throwable
, 당신은 또한 잡을 수 있습니다 InterruptedException
특별한 치료가 필요한 것입니다.보다 InterruptedException 다루기 상세 사항은.
확인되지 않은 예외만 포착하려는 경우 이 패턴을 고려할 수도 있습니다.
try {
...
} catch (RuntimeException exception) {
//do something
} catch (Error error) {
//do something
}
이렇게 하면 코드를 수정하고 확인된 예외를 발생시킬 수 있는 메서드 호출을 추가할 때 컴파일러가 이를 알려 주고 사용자는 이 경우에 무엇을 할지 결정할 수 있습니다.
오류 클래스의 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
. 방법에서 예외 거품을 절대적으로 가질 수 없다면 나쁜 연습이 아닙니다.
실제로 예외를 처리 할 수 없다면 나쁜 연습입니다.메서드 서명에 단순히 붙잡고 다시 던지거나, 더 나쁜 것보다 "던지는 것"을 추가하는 것이 좋습니다.
오류를 던지는 라이브러리를 사용하는 라이브러리를 사용하는 경우 때로는 던지기가 필요합니다. 그렇지 않으면 라이브러리가 응용 프로그램을 죽일 수 있습니다.
그러나 이러한 상황에서는 모든 throwable 대신 라이브러리가 던져진 특정 오류 만 지정하는 것이 가장 좋습니다.
Throwable은 Throw되는 것보다 모든 클래스의 기본 클래스입니다 (예외뿐만 아니라).OutOfMemoryError 또는 KernelError를 ( Java를 catch-java-java-lang-error"> 참조 할 수있는 경우) 할 수있는 일이 거의 없습니다.lang.error? )
예외를 잡는 것이 충분해야합니다.
논리에 따라 다르므로 옵션 / 가능성에 더 구체적이어야합니다.의미있는 방식으로 반응 할 수있는 구체적인 예외가있는 경우 먼저 그것을 잡을 수 있고 그렇게 할 수 있습니다.
모든 예외 및 오류 (예 : 오류 메시지가있는 종료)에 대해 동일한 작업을 수행 할 수 있습니다.
일반적으로 첫 번째 경우는 던지기를 붙잡을 수 없게됩니다.그러나 아직도 잡기를 잡는 것이 얼마나 많은 경우가 있습니다.
이는 매우 나쁜 습관으로 설명되어 있지만 때로는 희귀한 유용할 뿐만 아니라 필수인 경우도 있습니다.다음은 두 가지 예입니다.
사용자에게 의미 있는 전체 오류 페이지를 표시해야 하는 웹 애플리케이션에서.이 코드는 큰 일이므로 이런 일이 발생하는지 확인합니다. try/catch
모든 요청 처리기(서블릿, 스트럿츠 작업 또는 모든 컨트롤러 ....) 주변
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
를 잡고 아무 것도하지 않아도됩니다."는 괜찮습니까? " 여기에 많은 사람들이 후자에게 답변했지만 그것은 부작용입니다. 99 %의 시간의 99 %를 "소비하지 말아야 할 때, 예외를 폐기하거나 Throwable
또는 IOException
또는 무엇이든지 폐기하십시오.
예외를 전파하면 답변 (많은 질문에 대한 답변과 같은 답변)은 "의존합니다"입니다. 그것은 예외로하고있는 것에 달려 있습니다. 왜 당신이 그것을 잡는지 당신이 왜 당신이 그것을 잡는지에 달려 있습니다.
Throwable
를 잡으려고하는 이유의 좋은 예는 오류가있는 경우 일종의 정리를 제공하는 것입니다. 예를 들어 JDBC에서 트랜잭션 중에 오류가 발생하면 트랜잭션을 롤백하고 싶습니다.
try {
…
} catch(final Throwable throwable) {
connection.rollback();
throw throwable;
}
.
예외는 삭제되지 않지만 전파됩니다.
그러나 일반적인 정책으로서, 당신이 이유가없고 너무 게으른 이유가 너무 게으른 이유가 없기 때문에, 이유가 없기 때문에, 나쁜 아이디어가 불량하고 나쁜 생각을 볼 수 있습니다.
일반적으로 Error
s를 잡는 것을 피하고 싶지만 적어도 두 가지 특정 사례를 생각할 수 있습니다 :
- 오류에 대한 응답으로 응용 프로그램을 종료하고, 특히 무해한
AssertionError
입니다. - executorservice.submit () 사용자에게 예외를 다시 전달하여 처리 할 수 있습니다.
throwable 을 사용하면 오류 뿐만 아니라
를 다룹니다.예제.
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을 사용하는 경우 모든 예외를 잡을뿐만 아니라 모든 오류도 catch합니다.응용 프로그램에서 처리하려는 심각한 문제를 나타내는 JVM에 의해 오류가 발생합니다.그것에 대한 전형적인 예는 OutOfMemoryError 또는 StackOverflowerROR입니다.둘 다 응용 프로그램의 제어 가외의 상황에 따라 발생하며 처리 할 수 없습니다.그래서 당신이 던지는 것이 예외적 인 것일 것이라고 확신하지 않는 한 당신은 꽤 확신하지 않아야합니다.
일반적으로 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
가 포착되고 모든 예외는 기록만 남으므로 나머지 흐름이 계속됩니다.