포스트

예외 처리

예외 처리

예외 처리가 필요한 이유

예외 처리 구문이 없으면 if ~ else 구문으로 모두 처리해야 합니다. 이는 정상 구문과 예외 구문을 구분하기 힘들게 만들며 유지보수를 힘들게 합니다.

예외 계층

  • Throwable: 최상위 예외
  • Error:
    • 심각한 시스템 오류와 같이 애플리케이션에서 복구가 불가능한 시스템 예외
    • 이 예외를 잡으려고 해서는 안됨
  • Exception
    • 체크 예외
    • 단, RuntimeException은 예외
  • RuntimeException: 언체크 예외

체크 예외 vs 언체크 예외

  • 체크 예외: 예외를 잡아서 처리하지 않으면 항상 throws 키워드를 사용해서 던지는 예외를 선언해야 함
  • 언체크 예외: 예외를 잡아서 처리하지 않아도 throws 키워드를 생략 할 수 있음

체크 예외

  • Exception을 상속받은 예외는 체크 예외가 됨
1
2
3
4
5
public class MyCheckedException extends Exception {
  public MyCheckedException(String message) {
    super(message);
  }
}

처리 방법 1 - try ~ catch

1
2
3
4
5
6
public class Client {
  public void call() throws MyCheckedException {
    //문제 상황
    throw new MyCheckedException("ex");
  }
}
1
2
3
4
5
6
7
8
9
10
11
public class CheckedThrowMain {

  public static void main(String[] args) {
    Client client = new Client();
    try {
      client.call();
    } catch (MyCheckedException e) {
      System.out.println("예외 처리");
    }
  }
}

처리 방법 2 - throws

1
2
3
4
5
6
7
public class CheckedThrowMain {

  public static void main(String[] args) throws MyCheckedException {
    Client client = new Client();
    client.call();
  }
}

체크 예외 장단점

  • 장점: 개발자가 실수로 예외를 누락하지 않도록 컴파일러를 통해 잡아주기 때문에 어떤 체크 예외가 발생하는지 쉽게 파악 가능
  • 단점: 모든 체크 예외를 반드시 잡거나 던지도록 처리해야 하기 때문에 너무 번거로운 일이 됨

단점 예시

처리하지 못하면 throws 구문으로 반복해서 던져줘야 합니다.

언체크 예외

  • RuntimeException을 상속받은 예외는 언체크 예외가 됨

언체크 예외 장단점

  • 장점
    • 신경쓰고 싶지 않은 언체크 예외를 무시할 수 있음
    • 예외를 한 곳에서 공통 처리 할 수 있음
  • 단점: 개발자가 실수로 예외를 누락할 수 있음

공통 처리 예시

실무에서는 런타임 예외를 주로 사용합니다.

finally

자바는 어떤 경우라도 반드시 호출되는 finally 기능을 제공합니다.

필요 이유

try ~ catch로 예외를 받아 처리 하더라도, 또 다른 예외나 예상치 못한 상황이 발생할 수 있습니다. 이런 경우 파일이나 네트워크 리소스를 닫지 않으면 자원이 낭비되게 되는데, 이런 상황을 예방 하고자 필요합니다.

사용 방법

1
2
3
4
5
6
7
try{
  //정상 흐름
  }catch{
  //예외 흐름
  }finally{
  //반드시 호출해야 하는 마무리 흐름
  }
  • try ~ finally도 가능
1
2
3
4
5
try{
  //정상 흐름
  }finally{
  //반드시 호출해야 하는 마무리 흐름
  }

try-catch-resources

외부 자원을 사용하고 try가 끝나면 외부 자원을 반납하는 패턴이 반복되면서 편의 기능으로 도입되었습니다.

이를 사용하기 위해선 AutoCloseable 인터페이스를 구현해야 합니다.

1
2
3
public interface AutoCloseable {
  void close() throws Exception;
}
1
2
3
4
try(Resource resource = new Resource()){
  // 리소스를 사용하는 코드
  }catch{
  }

이렇게 finally를 구현하지 않아도 자동으로 close 메소드가 호출되어 처리 됩니다.

이외에 try ~ catch 사용 방법

catch 여러 개 선언

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class CheckedThrowMain {

  public static void main(String[] args) {
    Service service = new Service();
    try {
      service.catchThrow();
    } catch (MyCheckedException e) {

    } catch (RuntimeException e) {

    } catch (Exception e) {

    }
    System.out.println("정상 종료");
  }
}

위에서 부터 체크를 하므로 하위 타입이 위로 가야 합니다.

catch or 구문

1
2
3
4
5
6
7
8
9
10
11
public class CheckedThrowMain {

  public static void main(String[] args) {
    try {

    } catch (IllegalArgumentException | IllegalStateException e) {

    }
  }
}

e 변수는 공통 부모의 값만 참조할 수 있습니다.

참고

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.