자바의 예외처리

2020. 4. 18. 17:52Java

에러(Error) vs 예외(Exception)

  • 자바에서 에러는 정상적인 프로그램이 잡아낼 수 없는 치명적인 문제를 뜻한다. 즉, 에러가 발생하면 복구가 불가능하고 프로그램은 비정상적으로 종료된다. 대부분 runtime 중에 일어난다. 흔히 볼 수 있는 에러로 StackOverFlowError가 있다.
  • 반면 예외는 정상적인 프로그램이 잡아내길 원하는 조건을 뜻한다. 예외가 발생하면 프로그램이 종료될 수 있으나, 이는 try, catch, throw 등의 키워드로 복구가 가능하다. 모든 예외는 runtime 중에 일어난다.
  • 에러와 예외는 모두 java.lang.Throwable 클래스의 자식 클래스이다.

자바의 Error, Exception 클래스의 상속도

예외 종류 - Checked vs Unchecked

  Unchecked Checked
예외처리 여부 명시적으로 처리가 강제되지 않음 반드시 해야함
컴파일러의 확인 시점 실행 단계(Runtime Exception) 컴파일 단계
대표 예외

java.lang.IllegalArgumentException

java.lang.NullPointerException

java.lang.IOException

java.lang.SQLException

  • Unchecked

    아래 코드는 5를 0으로 나누기 때문에 java.lang.ArithmeticException이 발생한다. 컴파일 시점에는 컴파일러가 이를 확인할 수 없기 때문에 실행이 가능하다.

    public static void main(String[] args) { 
        int a = 5, b = 0; 
        System.out.println(a / b);
    } 
    output: java.lang.ArithmeticException: / by zero

    이는 try ~ catch를 사용해서 아래와 같이 예외 처리를 할 수 있다. 예제가 약간 이상하지만 예외가 발생할 경우, 다른 방식으로 처리할 수 있다는 개념을 가져가면 된다.

    public static void main(String[] args) { 
        int a = 5, b = 0; 
        try { 
            int c = a / b; 
        } 
        catch (ArithmeticException e) { 
            System.out.println(a - b);
        } 
    } 
    output: 5
  • Checked

    아래와 같은 코드는 컴파일이 불가능하다.

    public static void main(String[] args) {
        FileReader file = new FileReader("somefile.txt");
    }

    new FileReader() 는 Checked Exception인 FileNotFoundException을 Throw하는데 이를 처리하지 않았기 때문이다. 따라서 아래와 같이 코드를 수정해야 컴파일이 가능하다.

    public static void main(String[] args) {
        try {
            FileReader file = new FileReader("somefile.txt");
        } 
        catch (FileNotFoundException e) {
            System.out.println("파일이 없습니다.");
        }
    }

올바른 예외 처리

  • RuntimeExeception과 Exeception을 구분해서 사용해야 한다.

  • 예외 메세지가 예외에 대한 상세한 정보를 포함해야 한다. (이펙티브 자바 75)

  • 예외 처리와 로직 처리를 구분해야 한다. 로직을 위해 예외 처리를 사용하는 것은 가독성을 떨어트리고, 자원을 많이 소모한다(new 키워드를 사용하기 때문에).

    // 좋지 않은 예시
    try {
        for (int i = 0;; i++)
            array[i]++;
    } catch (ArrayIndexOutOfBoundsException e) {
    }
    
    // 올바른 예시
    for (int i = 0; i < array.length; i++)
        array[i]++;

    위 예시에서는 당연히 예외 처리를 사용하지 않은 방식이 더 깔끔해 보인다. 하지만 메서드들의 깊이가 깊어지면 예외 처리를 사용해서 코드를 짜는게 더 깔끔해보일 때가 있다. 하지만 예외 처리를 할 때, 어떤 메서드에서 예외를 발생하는지 확인하기가 어렵기 때문에 이는 좋은 방식이 아니다.

참고 사이트

http://www.nextree.co.kr/p3239/
https://www.geeksforgeeks.org/errors-v-s-exceptions-in-java/
https://howtodoinjava.com/java/exception-handling/checked-vs-unchecked-exceptions-in-java/
https://web.archive.org/web/20140430044213/http://c2.com/cgi-bin/wiki?DontUseExceptionsForFlowControl