본문 바로가기

DEVELOPER/Java

[JAVA 파헤치기] 예외 처리(Exception handling)

안녕하세요😎 백엔드 개발자 제임스입니다 :)

이번 포스팅은 자바에서 예외를 처리하는 방법에 대해서 정리하도록 하겠습니다. 우리는 프로그램 실행 중, 어떤 원인에 의해서 오작동을 하거나 비정상적으로 종료되는 것을 경험한 적이 있을 것입니다. 이러한 결과를 초래하는 원인을 프로그램 에러 또는 오류라고 합니다.

에러는 발생한 시점에 따라 다양하게 나눌 수 있습니다.

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

만약 프로그램이 실행된 상태에서 에러가 발생하면 프로그램은 어떻게 될까요? 아마 에러에 의해서 잘못된 결과를 얻거나, 프로그램이 비정상적으로 종료됩니다. 가령 중요한 프로그램 또는 웹이었다면 큰 문제가 될 것입니다. 이와 같은 런타임 에러를 방지하기 위해서는 프로그램의 실행 도중 발생할 수 있는 모든 경우의 수를 고려하여 대비할 필요가 있습니다.

이때 자바에서는 발생할 수 있는 오류를 '에러(Error)'와 '예외(Exception)' 로 구분합니다.

에러(Error) : 프로그램 코드에 의해서 수습될 수 없는 심각한 오류 (ex. 메모리 부족, 스택오버플로우 등)
예외(Exception) : 프로그램 코드에 의해서 수습될 수 있는 가벼운 오류

 


 

1. 예외 클래스의 계층 구조


전체 Exception 클래스 중 몇 개의 주요 클래스

위에서 발생할 수 있는 오류를 Error와 Exception으로 나눌 수 있다고 했는데요. 따라서 Object.Throwable의 자손은 Exception클래스Error클래스로 존재합니다. 그리고 각 클래스에는 다양하고 많은 클래스들이 존재합니다. 몇 가지 예를 들자면, IOException, ClassNotFoundException, RuntimeException(ArithmeticException, ClassCastException, NullPointerException, IndexOutOfBoundException 등이 있습니다.

대체로 RuntimeException과 그 외에 Exception으로 나뉘는데요. 이 두 가지는 발생 원인에서 차이를 갖습니다. 먼저 RuntimeException은 프로그래머의 실수로 발생하는 예외입니다. 반면 그 외에 Exception들은 대체로 사용자의 실수와 같은 외적인 요인에 의해 발생하게 됩니다.

 

#1. 프로그래머의 실수로 발생하는 예외

  • ArrayIndexOutBoundsException : 배열의 범위를 벗어났을 때 발생하는 예외
  • NullPointerException : 값이 null인 참조 변수의 멤버를 호출했을 때 발생하는 예외 (ex. 값이 null인 객체의 메서드 사용)
  • ClassCastException : 클래스 간의 형 변환을 잘못할 경우 발생하는 예외

#2. 사용자의 실수로 발생하는 예외

  • FileNotFoundException : 존재하지 않는 파일의 이름을 입력했을 때 발생하는 예외
  • ClassNotFoundException : 클래스의 이름을 잘못 입력했을 때 발생하는 예외
  • DataFormException : 입력한 데이터의 형식이 잘못된 경우 발생하는 예외

2. 예외 처리하기 (try-catch문)


예외 처리(Exception handling)는 프로그램 실행 시 발생할 수 있는 예기치 못한 예외에 대비하는 것을 말합니다. 즉, 프로그램이 실행되었으나, 예외로 인해 발생하는 비정상 종료를 막고, 정상적인 실행상태를 유지할 수 있도록 하는 것입니다.

예외를 처리하기 위해서는 try-catch문을 사용합니다.

try {
      // 예외가 발생할 가능성이 있는 문장들
} catch (Exception1 e1) {
      // Exception1 이 발생했을 경우, 이를 처리하기 위한 문장을 작성
} catch (Exception2 e2) {
      //  Exception2  이 발생했을 경우, 이를 처리하기 위한 문장 작성
} finally {
      // 예외 발생 여부에 관계없이 항상 수행되는 코드
      // finally 블럭은 try-catch문의 맨 마지막에 위치해야 함.
}
* catch와 finally는 생략이 가능합니다.

위 예제를 보다시피, 예외가 발생할 코드를 try { } 안에 작성합니다. try에 구문이 동작할 때 예외가 발생하면, catch 내에 코드가 작동합니다. 여기서 괄호 안에 적힌 Exception에 해당하는 catch 문으로 들어가서 동작하게 됩니다.


1) try 블럭 내에서 예외가 발생하지 않는 경우

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

위 코드는 예외가 발생하지 않은 경우입니다. 이 말은 즉, catch가 동작하지 않았다는 의미입니다. 따라서 콘솔 창에는 [1 2 3 5]만 출력됩니다.

 

2) try 블럭 내에서 작동 도중 예외가 발생할 경우

class test2 {
	public static void main(String args[]) {
    	System.out.println(1);
        
        try {
            System.out.println(0/0); // 0으로 나눔으로써 예외 발생
            System.out.println(2); // 실행 X
        } catch (ArithmeticException e) {
        	System.out.println(3); // 실행
        }
        
        System.out.println(4);
    }
}

이번에는 try 내에서 예외가 발생한 경우입니다. try 내에서 0/0를 출력하는 부분에서 예외가 발생했습니다. 여기서 잘 보면, 예외가 발생한 시점에서 바로 catch의 코드가 실행되는 것을 볼 수 있습니다. 따라서 콘솔 창에는 [1, 3, 4]가 출력됩니다.

catch의 매개변수로 어떤 특정한 예외를 작성할 수도 있지만,
예외의 부모 클래스인 Exception 클래스를 작성해서, 좀 더 포괄적이게 예외 처리를 할 수도 있습니다.
* 예외의 발생 원인을 알려주는 메서드
1) getMessage() : 발생한 예외 클래스의 인스턴스에 저장된 메시지를 얻음
2) printStackTrace() : 예외발생 당시의 호출 스택(Call Stack)에 있었던 메서드의 정보와 예외 메시지를 화면에 출력

 

3) 의도적으로 예외 발생시키기

  • 연산자 new를 이용해서 발생시키려는 예외 클래스의 객체를 생성
  • throw 키워드 사용
class test3 {
	public static void main(String args[]) {
    	try{
            Exception e = new Exception("예외 발생");
            throw e;
            
            // throw new Exception("예외 발생2");
        } catch (Exception e) {
        	System.out.println("에러 메시지 : " + e.getMessage());
            e.printStackTrace();
        }
        System.out.println("프로그램 정상 종료");
    }
}
  • 결과
    • 에러 메시지 : 예외 발생
    • java.lang.Exception : 예외 발생
      • at test3.main(test.java:4)
    • 프로그램 정상 졸료

 

* 용어 참고
throw : 발생시키다
catch : 잡아내다

 

3. 메서드 예외 선언 (throws)


void method() throws Exception1, Exception2,,, {

	//구현부
}

지금까지 예외를 처리하기 위한 방법으로 try-catch에 대해서 알아보았습니다. 

이 외에도 예외를 처리하는 방법이 있는데요. 예외를 처리하고 싶은 메서드에 선언하는 방법입니다. 위에 적힌 방법대로 메서드의 선언부에 키워드 throws를 사용해서 발생 가능성이 있는 예외를 적어주면 됩니다. 쉼표(,)를 통해서 예외를 여러 개 처리할 수도 있습니다.

try-catch 에 비해 굉장히 간략해졌는데요. 그럼에도 동일한 기능을 보일 뿐더러, 코드 가독성도 증가하는 효과를 볼 수 있습니다.

반응형