개발을 하다 보면 exception 일 때 try~catch
로 처리하는 경우가 있고, Runtime Exception
으로 처리되게 하는 경우가 있다. 처리하는 방식이 어떻게 다른지, 어떤 방법이 더 선호되는지 알아보자.
우선 Exception 의 개념에 대해 먼저 알아보자.
Exception
은 한마디로 예외이다. 그렇다면 예외와 에러의 차이는 무엇일까?
예외
란 개발자가 구현한 로직 내에서 발생하는 것으로, 예측하여 처리가 가능하다.에러
란 시스템 내 비정상적인 상황이 생겼을 때 발생하며, 미리 처리 및 예측이 불가하다.이제 Exception 에 대해 간단히 알았으니, Exception 에 어떤 종류가 있는지 알아보자.
다음 그림을 보면 Exception 이 Checked Exception
과 Unchecked Exception
두가지로 나누어져 있는 것을 볼 수 있다.
이제 이 두가지의 차이를 알아보자.
compile 단계에서 발생하는 exception 으로 반드시 예외에 대한 처리를 선언해야 한다.
ex) IOException, FileNotFoundException 등
try ~ catch
로 예외 처리
public void test() {
try {
File file = new File("text.txt");
FileReader fr = new FileReader(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
throws FileNotFoundException
으로 예외를 전가, 상위 메서드의 선언부에도 시그니처 선언public void test() throws FileNotFoundException {
File file = new File("text.txt");
FileReader fr = new FileReader(file);
}
실행 단계에서 발생하는 exception 으로 예외에 대한 처리를 미리 할 수 없다.
ex) RuntimeException, NullPointerException, IllegalArgumentException 등
public static void main(String[] args) {
int[] array = new int[5];
System.out.println(arr[6]); // ArrayIndexOutOfBoundsException 발생
}
checked exception 은 예외처리를 강제하여, try~catch 를 사용하여 예외를 잡거나, throws Exception 으로 예외를 전가하여 예외를 처리해야하고, 예외를 처리하 않으면 컴파일 오류가 발생하는 반면, RuntimeException 의 경우 예외 처리를 강제하지 않으며, 실행 시 예외가 발생하므로 컴파일 오류가 발생하지 않는다.
일반적으로 스프링에서 Checked Exception 은 예외 발생 시 롤백이 되지않고, Unchecked Exception은 예외 발생 시 롤백이 되는 것으로 알고 있다.
하지만 이는 스프링의 기본 설정일 뿐이고, Checked Exception 또한 롤백되게 설정할 수 있다.
@Override
public boolean rollbackOn(Throwable ex) {
return (ex instanceof RuntimeException || ex instanceof Error);
}
@Transactional(rollbackFor = {RuntimeException.class, Error.class})
public void test() {
}
그렇다면 Checked Exception 도 롤백되게 설정하려면 어떻게 해야할까?
@Transactional(rollbackFor = Exception.class)
public void test() {
}
rollbackFor = Exception.class
로 작성하면, 모든 Exception 에 대해 롤백된다.실무에서 경험해보면 try ~ catch 를 사용하여 예외를 처리하는 경우를 본 경우가 드물다. 또한 RuntimeException 을 사용하는 것을 권장한다. 왜 그럴까?
Checked Exception 을 사용할 때의 몇 가지 단점 때문이다.
Checked Exception 은 예외를 복구할 수 있을 때 사용한다.
Checked Exception 을 사용하는 경우는 예외를 복구할 수 있는 경우이다. 하지만 일반적으로 예외를 복구할 수 있는 상황은 거의 없다. 예를 들어 사용자가 잘못된 값을 보낸 경우 exception 이 발생했을 때, exception 이 발생한 후 해당 프로세스가 종료되며, 재요청을 보내는 것이지 예외가 복구되는 것이다 아니다.
open / closed 원칙 위배
checked exception 에서 예외를 상위 메소드로 던질 경우, 상위 메소드 선언부에도 시그니처를 변경해야한다. 만약 하위 메소드에서 checked exception 을 발생시키면, 이를 호출하는 모든 상위 메서드의 선언부를 변경해야한다. 이는 기존 코드의 변경을 최소화하여 수정을 가능하게 해야한다는 open/closed 원칙에 위배된다.
다른 언어들은 checked exception 이 없다.
java 외에 다른 프로그래밍 언어는 checked exception 이라는 개념이 없다. 다른 언어로 개발한다고 exception 처리에 문제가 있는 것은 아니므로 checked exception 이라는 개념이 굳이 필요없다. 물론 장점도 있지만 종속성 비용이 더 크다.
Checked Exception 에 대한 논란은 지속되어 왔다. Checked Exception 은 자바의 실수다 아니다로 많은 논란이 있었는데, 현재는 Checked Exception 을 사용하지 않는 방향으로 논란이 종결된 것 같다. Checked Exception 은 대규모의 프로그래밍을 개발할 때 오히려 생산성을 떨어트린다는 결과가 나왔고, 현재 Java 도 함수형 인터페이스에서 Checked Exception 을 허용하지 않고 있다.
이렇게 Exception 에 관련해서 개념과 논란에 대해 알아보며, 어떤 처리 방식이 선호되고, 단점이 무엇인지 알게된 시간이었다.
https://www.nextree.co.kr/p3239/
https://jangjjolkit.tistory.com/3
https://velog.io/@sangmin7648/당신의-Checked-Exception은-필요-없다
https://inpa.tistory.com/entry/JAVA-☕-예외-던지기throw-예외-연결Chained-Exception
https://velog.io/@eastperson/Java%EC%9D%98-Checked-Exception%EC%9D%80-%EC%8B%A4%EC%88%98%EB%8B%A4-83omm70j