존재하지 않은 파일을 열려고 한다거나, 숫자를 0으로 나눈다거나... 앞에서 입출력을 수행할 때 IOException을 throw했듯, Java는 이런 예외가 발생할 수 있다고 판단되는 구문들을 모두 잡아두고 예외처리를 수행하도록 강제하고 있다.
이는 작성이 번거롭다는 단점이 될 수도 있지만 동시에 빠른 디버깅과 유지보수를 가능하게 한다.
try {
...
} catch (예외1) {
...
} catch (예외2) {
...
} finally {
...
}
try 문을 수행하면서 예외가 발생하는지 체크하고, 예외가 발생한다면 예외 상황에 맞는 catch문을 수행한다.
한편 예외가 발생했건 아니건 간에 finally 구문이 존재한다면, try 문과 (예외 발생 시) catch 문을 모두 수행한 뒤 마지막에 finally의 내용을 수행한다.
매우 다양한 Exception들이 이미 존재하지만, 우리는 그 예외들을 상속해서 필요 시 우리만의 예외를 만들 수도 있다.
class MyException extends Exception {}
class MyRuntimeException extends RuntimeExceptions {}
Exception은 컴파일시 발생하는 예외이고 RuntimeException은 실행 중 발생하는 예외이다. 작성 중 예측 가능한 경우 Exception, 런타임 에러가 예상되는 경우 RuntimeException을 이용하자.
이렇게 직접 작성한 에러는 본인의 코드 내에서 특정 조건이 성립할 때 throw new MyException; 처럼 던지도록 해 사용할 수 있다.
try ... catch 구문 대신, 메서드에 throws XXXException 을 추가해서 호출한 곳에서 예외를 처리할 수 있도록 위로 던지는 방법이 있다.
public void exMethod(String str) throws IOException {
...
}
이 방법을 사용하게 되면 예외처리를 뒤로 미루듯, 해당 메서드를 호출한 메서드에서 해결하도록 할 수 있다. 해당 메서드 호출 후 예외 발생 시 처리방법이 다르게 적용되어야 하는 경우 유용하게 사용될 수 있다.
예외를 처리하는 위치는 프로그램의 수행여부를 결정하기도 하고 트랜잭션 처리와도 밀접한 관계가 있어서 이를 잘 컨트롤하는 것은 대단히 중요하다.
하지만 그냥 throws만을 남발하게 되면 최상위단에서 수많은 예외를 혼자 처리해야 할 수 있으므로 필요시에 사용하도록 하자.
예외 처리 위치가 트랜잭션 처리와 왜 관계가 있는지 알아보자.
트랜잭션이란 쪼갤 수 없는 업무의 최소 단위를 뜻한다. 어떠한 트랜잭션의 수행 중 에러가 발생하면 거기서 멈추는 것이 아니라 트랜잭션이 시작되기 전의 상태로 돌아와야 한다. DB 처리를 수행할 때 트랜잭션이라는 단어를 들어보게 될 것이다. DB 상태 변경 중 에러가 발생하면 냅다 거기서 멈추면 안 되고, 아예 처리 전의 상태로 돌아올 수 있도록 처리해야 한다.
따라서 아래와 같이 예외처리의 위치를 설정해 트랜잭션을 관리해야 한다.
A 트랜잭션() {
try {
업무 1();
업무 2();
업무 3();
} catch(예외) {
진행사항 모두 취소();
}
}
업무 1() throws 예외 { ... }
업무 2() throws 예외 { ... }
업무 3() throws 예외 { ... }
이 글은 점프 투 자바를 읽고 스터디한 글입니다.