java에서 exception

주로 문법과 활용방법에관해 다루는 포스트이다.

  • try-catch-final
  • throw, throws
  • checked, unchecked exception
  • custom exception

관련 포스트

프로그래밍에서 예외 - 기초 개념
java에서 exception
wep api 서비스 application에서 exception

try-catch-final

예외가 발생할 가능성이 있다면 이 부분에 대하여 처리할수있다.

1
2
3
4
5
6
7
8
9
10
11
try {
doSomething();
} catch (CustomException e){
log.warn();
//do nothing
} catch (NullPointException e){
log.error();
rollback();
} final{
close();
}

try 를 수행하다가 오류가나면 catch 가 처리하고,
try나 catch가 끝나면, final 이 수행된다.

trt에서 발생하는 예외 종류에 따라 처리 방법을 다르게 할 수 있어서, 하나의 try블럭에 여러개 catch가 대응할수 있다.

처리방법으로는 상황에 따라 크게 다르다.

  • 로그를 남긴다
  • 데이터를 원상복구한다
  • 예외를 던진다

throw/ throws

얼핏보면 비슷해보이지만 성격이 완전히 다른 친구들이다. (overloading vs overriding이 연상된다.)

throw

throw 는 예외를 던진다 는 표현이 정말 잘 어울린다. 개발자의 판단으로 예외를 발생시킨다.

함수를 작성한다고 가정하자. 일반적으로 함수는 인풋을 받아 처리하여 아웃풋을 준다.
하지만 이 함수를 호출하는 다른 함수(caller)들은 내부를 모르고 사용하기때문에 원치 않는 상황이 생길 수 있다.

  • 원하는 인풋의 형태가 아닌경우 (숫자를 원했지만, 특수문자가 들어옴)
  • 원하는 인풋의 범위가 아닌경우 (양수만 취급하는데 -1이 들어옴)
  • 원하는 시간내에 처리되지않는경우 (2초이내에 처리되지않으면 예외로처리하겠다!)

아래는 나눗샘을 하는 함수의 예시이다. 0으로 나누는경우 RuntimeException을 명시적으로 던지도록 하였다.

1
2
3
4
5
6
public double divide(double target, double denominator) {
if (denominator == 0) {
throw new RuntimeException();
}
return target/denominator;
}

throws

throws는 성격이 다르다. 예외가 발생했을때의 처리를 호출자에게 위임한다.

1
2
3
4
5
6
7
8
// "1"이라는 문자를 숫자1로 바꿔주는 함수
int parseOne(String s) throws ParseException {
if ("1".equals(s)) {
return 1;
} else {
throw new ParseException(s, 1);
}
}

throws ParseException를 적어주었다면, 해당 함수에서 ParseException가 발생한다면 예외로 인해 application이 동작을 멈추지않는다.(당장은)

호출한 caller는 예외발생을 전달받으며, try-catch를 통해 아무일도 없었다는듯이 이후 로직을 진행할수도 있다. 그대로 예외를 던져버리거나 자신이 만든 Exception으로 래핑할수도있다. callee와 마찬가지로 caller에게 위임할수도 있다.

throws의 과도한사용은 예외에 대한 책임소재가 불분명해지고, 트래킹도 힘들기때문에 추천하지않는다.
일반적으로 util 성격을 띄는 모듈에서 자주사용하고, 이 util사용시 오류핸들링을 caller에게 위임한다.

checked exception / unchecked exception

exception-class-hirarc.jpeg

checked exception과 unchecked exception의 차이점은 예외의 처리를 강제하는가?이다.

checked exception

예외처리를 강제한다. try-catch를 통해 예외가 발생했을때의 상황에대해 처리리를 해주어야한다. 해당 메서드에서 처리하지 않으려면 throws를 통해 상위 메서드에 책임을 위임 할 수 있다. 하위메서드에서 throws를 한다면 caller인 상위 메서드에서 책임을 가진다. 마찬가지로 throws를 통해 더 상위의 메서드에게 위임할수있다.

하지만 상위메서드에 위임하는 상위메서드의 책임을 가중시키고 책임소제가 명확해지지 않는 등 단점이 많기때문에 추천하지 않는다.

대표적으로 IOException 이 있다.

unchecked exception

예외 처리를 강제하지 않는다. runtime exception을 상속한다. 처리를 강요하지 않지만 try-catch로 감싸 처리를 해도 상관없다.

대표적으로 null point exception이 있다.

custom exception - 자신만의 예외

unchecked exception기준으로는 RuntimeException만 상속받는다면 기본적인 준비는 끝이다.
필요하다면 예외에 사용할 다른 정보들을 추가로 받을 수 있게 한다.
응답 코드 메시지를 아래처럼 enum 으로 관리한다고 가정한다면,

1
2
3
4
5
6
7
8
9
10
public enum ResponseCode {
SUCCESS(0, "성공"),
NOT_EXIST(1001, "존재하지 않음"),
INVALID_STATE(1004, "올바르지 않은 상태"),
UNKNOWN(-1, "알 수 없는 오류");
...

private final int code;
private final String message;
}

ResponseCode를 통해서 생성하도록 할 수 있다.

1
2
3
4
5
6
7
8
9
public class CustomException extends RuntimeException {
private int code;
pirvate String message;

CustomException(ResponseCode responseCode){
this.code = responseCode.getCode();
this.message = responseCode.getMessage();
}
}

Comments