라봉이의 개발 블로그

java의 정석 8강. 예외처리(상) 본문

Java/Java의 정석 읽고 정리

java의 정석 8강. 예외처리(상)

Labhong 2018. 6. 3. 19:26
반응형

1. 예외처리

1.1 프로그램 오류


프로그램 오류는 컴파일 에러런타임 에러가 있는데 그 중 런타임 에러에러와 예외, 2가지 종류가 있다.

  • 에러: 프로그램 코드에 의해서 수습될 수 없는 심각한 오류

  • 예외: 프로그램 코드에 의해서 수습될 수 있는 다소 미약한 오류



1.2 예외처리의 정의와 목적


프로그램 실행도중에 발생하는 에러는 발생하면 복구할 수 없는 심각한 오류지만, 예외는 이에 대한 처리를 미리하면 프로그램의 비정상 종료를 막을 수 있다.



1.3 예외처리구문 try-catch


예외를 처리하기 위한 구문은 다음과 같다.

try {
    // 예외가 발생할 가능성이 있는 문장들을 넣는다.
} catch (Exception1 e1) {
    // Exception1이 발생했을 경우, 이를 처리하기 위한 문장 넣는다.
} catch (Exception2 e2) {
    // Exception2가 발생했을 경우, 이를 처리하기 위한 문장 넣는다.
}
...
} catch (ExceptionN eN) {
    // ExceptionN 이 발생했을 경우, 이를 처리하기 위한 문장 넣는다.
}


catch문이 여러개 있지만 이 중 발생하는 예외의 종류와 일치하는 단 한 개의 catch 블럭만 수행된다.


예제 1)

public class Main {
    public static void main(String[] args) {
        try {
        } catch (Exception e) {
            try {
            } catch (ArithmeticException e) {   // 에러: 같은 이름의 참조변수를 사용함
            }
        }
    }
}


위의 예제는 catch 블럭 내에 try-catch문이 포함된 경우, 같은 이름의 참조변수를 사용했기 때문에 오류가 났다. 각 catch 블럭에 선언된 두 참조변수의 영역이 서로 겹치기 때문에 다른 이름을 사용해서 구별해야한다.


예제 2)

public class Main {
    public static void main(String[] args) {
        int number = 100;
        int result = 0;

        for(int i = 0; i < 10; i++) {
            result = number / (int)(Math.random() * 10);
            System.out.println(result);
        }
    }
}

실행결과:

16

33

Exception in thread "main" java.lang.ArithmeticException: / by zero

at com.company.Main.main(Main.java:9)


위의 예제는 Math.random() 값이 어쩌다 0이 나와서 number를 0으로 나누었기 때문에 생기는 예외이다.

number를 0으로 나누려 했기 때문에 ArithmeticException이 발생했고 발생위치는 Main.java 파일의 9번째 줄이라는 것을 알 수 있다.


어디서 왜 일어났는 지 알았기 때문에 이번엔 try-catch를 추가하여 예외처리를 해보자.

public class Main {
    public static void main(String[] args) {
        int number = 100;
        int result = 0;

        for(int i = 0; i < 10; i++) {
            try{
                result = number / (int)(Math.random() * 10);
                System.out.println(result);
            } catch (ArithmeticException e){
                System.out.println("0");
            }
        }
    }
}


이제는 Math.random()이 0이 나오게 되면 catch 구문으로 들어가서 0을 출력하게 되고 계속해서 for문을 동작하게 된다.

예외처리 하지 않았다면 0이 나오는 순간 프로그램은 비정상 종료를 할 것이다.


1.4 try-catch문에서의 흐름


public class Main {
    public static void main(String[] args) {
        System.out.println(1);
        try {
            System.out.println(2);
            System.out.println(3/0);
            System.out.println(4);
        } catch (Exception e) {
            System.out.println(5);
        }
        System.out.println(6);
    }
}

출력 결과:

1

2

5

6


try문에서 오류가 생기자마자 바로 catch 문으로 넘어가기 때문에 4는 출력이 되지 않는다.



1.5 예외 발생시키기


키워드 throw를 사용해서 프로그래머가 고의적으로 예외를 발생시킬 수 있다. 방법은 다음과 같다.

  1. 먼저 연산자 new를 이용해서 발생시키려는 예외 클래스의 객체를 만든 다음
    Exception e = new Exception("고의로 발생시킴");

  2. 키워드 throw를 이용해서 예외를 발생시킨다.


public class Main {
    public static void main(String[] args) {
        try {
            Exception e = new Exception("고의로 발생시킴");
            throw e;
        } catch (Exception e) {
            System.out.println("에러 메세지: " + e.getMessage());
            e.printStackTrace();
        }
        System.out.println("프로그램이 정상 종료되었음");
    }
}
출력 결과:
에러 메세지: 고의로 발생시킴
java.lang.Exception: 고의로 발생시킴
at com.company.Main.main(Main.java:6)
프로그램이 정상 종료되었음


1.6 예외 클래스의 계층 구조

사진을 보면 알 수 있듯이 Exception과 Error 클래스 역시 Object 클래스의 자손들이다.
모든 예외의 최고 조상은 Exception이며, 상속 계층도를 Exception클래스부터 도식화 하면 다음과 같다.


그림에서 볼 수 있듯이 예외 클래스들은 다음과 같이 두 개의 그룹으로 나뉜다.

  • RuntimeException클래스와 그 자손클래스들
  • Exception클래스와 그 자손클래스들

RuntimeException클래스는 주로 프로그래머의 실수에 의해 발생하는 오류이고 그 외 Exception 클래스는 사용자의 실수와 같은 외적인 요인에 의해 발생하는 예외이다.

이 두 개의 오류의 차이점컴파일 시의 예외처리 체크 여부이다.
RuntimeException클래스들 그룹에 속하는 예외가 발생할 가능성이 있는 코드에는 예외처리를 하지 않아도 컴파일 시 문제가 되지 않지만 Exception클래스들 그룹에 속하는 예외가 발생할 가능성이 있는 예외는 반드시 예외처리를 해야하며 그렇지 않으면 컴파일 에러가 발생한다.


반응형
Comments