티스토리 뷰

프로그래밍 언어/Java

예외처리

빵파레2 2019. 6. 17. 00:07

1. 프로그램 에러 또는 오류


프로그램이 실행 중 어떤 원인에 의하여 오작동을 하거나 비정상적으로 종료되는 경우를 말한다.

발생시점에 따라 '컴파일 에러' 와 '런타임 에러' 로 나눌 수 있다.

이 외에도 '논리적 에러' 가 있다.

 

 

자바에서의 프로그램 에러

 

컴파일 에러 : 컴파일 시에 발생하는 에러
런타임 에러 : 실행 시에 발생하는 에러
논리적 에러 : 실행은 되지만, 의도와 다르게 동작하는 것

 

 

2. 런타임 에러


컴파일러에 의해 소스코드의 기본적인 사항의 에러는 걸러질 수 있지만 실행 도중에 발생할 수 있는 잠재적인 오류 (런타임 에러) 까지 검사할 수 없다.

자바에서는 런타임 에러를 '에러(Error)' 와 '예외(Exception)' 두가지로 구분한다.

에러는 메모리 부족(OutOfMemoryError) 이나 스택오버플로우(StackOverflowError) 와 같이 일단 발생하면 복구할 수 없는 심각한 에러이다.

예외는 발생하더라도 수습될 수 있는 비교적 덜 심각한 에러이다.

 

 

3. 런타임에러의 계층구조


자바에서는 런타임에러 (Exception, Error)를 클래스로 정의한다.

 

 

 

4. Exception 클래스 계층구조


Exception 클래스와 RuntimeException 클래스 중심의 계층구조

 

RuntimeException 클래스들은 주로 프로그래머의 실수로 발생하는 예외이다.

IndexOutOfBoundsException : 배열의 범위를 벗어날 경우

NullPointerException : 값이 null인 참조변수의 멤버를 호출하려고 할 경우

ClassCastException : 클래스간의 형변환을 잘못한 경우

ArithmeticException : 정수를 0으로 나누려고 할 경우

DataFormatException : 입력한 데이터 형식이 잘못된 경우

 

RuntimeException 을 제외한 Exception 클래스들은 주로 사용자의 실수와 같은 외적인 요인에 의해 발생하는 예외이다.

 

 

예외처리하기


프로그램의 실행도중에 발생하는 에러는 어쩔 수 없지만, 예외는 프로그래머가 이에 대한 처리를 미리 해주어야 한다.

 

예외처리의 정의 : 프로그램 실행 시 발생할 수 있는 예외의 발생에 대비한 코드를 작성하는 것

예외처리의 목적 : 프로그램의 비정상 종료를 막고, 정상적인 실행상태를 유지하는 것

 

발생한 예외를 처리하지 못하면, 프로그램은 비정상적으로 종료된다.

그리고 처리되지 못한 예외 (uncaught exception) 는 JVM의 '예외처리기(UncaughtExceptionHandler)' 가 받아서 예외의 원인을 화면에 출력한다.

 

try-catch문

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

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

또한 try 블럭에서 예외가 발생하면, 예외가 발생한 위치 이후에 있는 try 블럭의 문장들은 수행되지 않으므로, try 블럭에 포함시킬 코드의 범위를 잘 선택해야 한다.

 

try문에서 예외가 발생하면 해당 예외에 맞는 클래스의 인스턴스가 생성된다.

그 다음 첫번째 catch 블럭부터 차례로 내려가면서 catch블럭의 () 내에 선언된 참조변수의 종류와 생성된 예외클래스의 인스턴스에 instanceof 연산자를 이용해서 검사하여 검사결과가 true인 catch 블럭을 찾는다.

만약 검사결과가 true인 catch문이 단 하나라도 없다면 예외는 처리되지 않는다.

 

 

예외 발생시키기


키워드 throw를 사용해서 프로그래머가 고의로 예외를 발생시킬 수 있다.

 

ex1)

class ExceptionEx {
   public static void main(String[] args) {
      throw new Exception("고의로 예외 발생");
   }
}

위의 코드는 에러를 발생시키며 컴파일이 완료되지 않는다.

즉, Exception 클래스들 (Exception클래스와 그 자손들) 이 발생할 가능성이 있는 문장들에 대해 예외처리를 해주지 않으면 컴파일조차 되지 않는다.

 

ex2)

class ExceptionEx2 {
   public static void main(String[] args) {
      throw new RuntimeException("런타임 exception 발생");
   }
}

이전 예제와 달리 위의 예제는 성공적으로 컴파일 되지만 RuntimeException이 발생하여 비정상적으로 종료된다.

즉, 명백히 RuntimeException을 발생시키는 코드가 있고 이에 대한 예외처리를 하지 않았음에도 성공적으로 컴파일 된다. (컴파일은 됨)

RuntimeException 클래스와 그 자손들에 해당하는 예외는 프로그래머가 실수로 발생시키는 것들이기 때문에 예외처리를 강제하지 않는다.

컴파일러가 예외처리를 확인하지 않는 RuntimeException 클래스들은 'unchecked 예외' 라고 부르고,

예외처리를 확인하는 Exception 클래스와 그 자손들은 'checked 예외' 라고 부른다.

 

 

메서드에 예외 선언하기


키워드 throws를 사용해서 예외를 메서드에 선언할 수 있다.

이 경우에는 보통 RuntimeException 클래스들이 아닌 반드시 처리해주어야 하는 예외들만 선언한다.

사실 예외를 메서드의 throws에 명시하는 것은 예외를 처리하는 것이 아니라, 자신 (예외가 발생할 가능성이 있는 메서드)을 호출한 메서드에게 예외를 전달하여 예외처리를 떠맡기는 것이다. 

 

계속해서 예외처리를 떠맡기다 보면 최초 호출 지점인 main 메소드에 도달하게 되고 main 메소드에서도 예외를 처리하지 않으면 JVM의 예외처리기에 의해 처리된다.

 

 

finally블럭


finally 블럭은 try-catch문과 함께 예외의 발생여부에 상관없이 실행되어야할 코드를 포함시킬 목적으로 사용된다.

try-catch문의 끝에 선택적으로 덧붙여 사용할 수 있다.

 

 

사용자정의 예외 만들기


Exception 혹은 RuntimeException 클래스를 상속받아서 직접 예외를 만들 수 있다.

'checked 예외'는 반드시 예외처리를 해주어야 하기 때문에 예외처리가 불필요한 경우에도 try-catch문을 넣어서 코드가 복잡해지기 때문에 최근에는 RuntimeException을 상속받아서 작성하는 쪽으로 바뀌고 있다.

 

ex)

public class DuplicateUserException extends RuntimeException {

   public DuplicateUserException(String msg) {
      super(msg);
   }
}

 

 

참고자료


남궁 성 지음, Java의 정석, 도우출판

'프로그래밍 언어 > Java' 카테고리의 다른 글

컬렉션 프레임워크  (0) 2019.06.18
java.lang 패키지  (0) 2019.06.17
객체지향 프로그래밍3  (0) 2019.06.06
객체지향 프로그래밍2  (0) 2019.06.04
객체지향 프로그래밍  (0) 2019.06.02