티스토리 뷰
자바를 처음 접한지는 몇년이 되었지만... 그리고 예외에 대해서 학습할 때부터 예외의 종류를 대충 알고있었지만, 자바를 사용하니 왜 예외의 종류를 아는 것이 중요한지 느꼈다.
예를 들어 Thread.sleep() 메서드의 경우 InterruptedException을 발생하고, try catch를 통해서 해결하거나 메서드에서 throw 하는 방식을 취해야하는데, 이것은 강제된다.
반면에, 0으로 나누거나, IndexOutOfBoundsException 같은 경우는 try catch로 처리해 주지 않아도 된다.
왜 그럴까?
1. Checked Exception
Checked Exception은 컴파일타임에 확인되는 예외들이다.
만약 메서드 내에서의 코드 일부분이 checked exception을 throw한다면, 메서드는 예외를 처리하거나(try catch 사용), throws 키워드를 통해서 예외를 명시해야한다.
Checked exception은 JVM의 일부가 아니라 자바의 일부이다.
2. Unchecked Exception
Unchecked Exception은 컴파일 타임에 확인되지 않는 예외들이다.
C++에서는 모든 예외들이 unchecked라서 컴파일러가 특정 예외를 다루지 않아도 된다.
자바에서는 Error와 RuntimeException 클래스의 하위 클래스들이 unchecked exception이다.
그외 나머지는 모두 checked exception이다.
대표적인 예로서 다음과 같은 예외들이 있다.
- ArrayIndexOutOfBoundsException (JRE가 자동으로 던지는 예외)
- NullPointerException (JVM이 던지는 예외)
- ArithmeticException
3. Lombok의 @SneakyThrows
(1) lombok의 @sneakyThrows source code :
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.SOURCE)
public @interface SneakyThrows {
/** @return The exception type(s) you want to sneakily throw onward. */
Class<? extends Throwable>[] value() default java.lang.Throwable.class;
//The fully qualified name is used for java.lang.Throwable in the parameter only. This works around a bug in javac:
// presence of an annotation processor throws off the type resolver for some reason.
}
- 메서드와 생성자에 사용할 수 있는 lombok annotation이다. (Target 참고)
- 메서드 시그니처에 checked exception을 명시 하지 않고 throw할 수 있도록 해줌으로서 효과적으로 unchecked exception을 모방할 수 있다. java compiler가 checked exception을 unchecked처럼 처리하도록 속이는 방법이다.
- 하지만 sneakyThrows의 문제점은 예외를 결국에는 잡고 싶은데, 자바 컴파일러는 특정 exception 타입에 대해서 exception handler를 사용하여 sneakily thrown checked exception을 catch하는 것을 허용하지 않는다. (아래 문제점 참고)
- 바이트코드 조작이나 Thread.stop(Throwable)을 사용해서 checked exception을 throw할 수 있지만, 복잡하고 추천되지 않는다.
- @SneakyThrows는 Runnable 인터페이스같이 매우 제한적인 메서드로부터 예외를 발생시켜야 할 때 유용하다.
(2) @sneakyThrows의 문제점
선언되지 않은 checked exception을 잡을 수 없다.
sneakily thrown된 아래 메서드를 catch하려고 한다면, 컴파일 에러가 발생한다.
예를들어, 아래코드는 호출한 메서드에서 컴파일에러를 받게 된다.
[실행 결과]
sneakyThrow를 사용하지 않으면 아래와 같이 컴파일 에러가 호출시 발생하여 catch 가능하다.
[실행 결과]
하지만 아래 코드에서 sneakily thrown된 IOException을 catch하려고 한다면, 컴파일 에러를 받을 수가 없다.
런타임 에러(unchecked exception)같이 checked exception을 처리하기 때문이다.
[실행 결과]
[또 다른 테스트]
public class Test {
public static void main(String[] args) throws RuntimeException {
int a = 0;
int b = 12;
double result = divideByZero(a, b);
System.out.println(result);
}
private static double divideByZero(int a, int b) {
return (double) b / a;
}
}
[실행 결과] infinity가 출력된다.
public class Test {
public static void main(String[] args) {
int a = 0;
int b = 12;
double result = divideByZero(a, b);
System.out.println(result);
}
@SneakyThrows
private static double divideByZero(int a, int b) {
return (double) b / a;
}
}
[실행 결과] infinity가 출력된다.
[출처]
https://www.geeksforgeeks.org/checked-vs-unchecked-exceptions-in-java/
'Programming > Java' 카테고리의 다른 글
Scanner와 BufferedReader / BufferedWriter의 차이점과 사용법 (0) | 2023.06.05 |
---|---|
try-with-resources 적용 후기 (0) | 2023.03.17 |
@SafeVarargs Annotation (추가 학습 필요) (0) | 2022.12.19 |
Trouble Shooting: java list ( Arrays.asList(), List.of() )사용시 UnsupportedOperationException 해결법 (0) | 2022.12.19 |
Junit5 (0) | 2022.12.01 |
- Total
- Today
- Yesterday