[Java] Exception Handling

Jane·2020년 12월 4일
5
post-thumbnail

Error vs. Exception

  • 오류(error): 프로그램 코드에 의해서 수습될 수 없는 심각한 오류
    → 시스템 레벨에서 프로그램에 심각한 문제를 야기하여 실행 중인 프로그램을 종료시킨다.
    • e.g. OutOfMemoryError, StackOverflowError
  • 예외(exception): 프로그램 코드에 의해서 수습될 수 있는 다소 미약한 오류
    → 실행 중인 프로그램을 비정상적으로 종료시키지만, 개발자가 발생할 수 있는 상황을 미리 예측하여 처리할 수 있다.

예외 처리(Exception handling)

  • 프로그램의 비정상 종료를 막고, 정상적인 실행상태를 유지하기 위해 프로그램 실행 시 발생할 수 있는 예외에 대비한 코드를 작성하는 것

throw

  • 연산자 new를 이용해서 예외 클래스의 객체를 만든 다음 키워드 throw를 이용해서 고의로 예외를 발생시킬 수 있다.
class Main {
    public static void main(String[] args) {
        try {
            Exception e = new Exception("throw로 예외 강제 발생");
            throw e;
            // throw new Exception("예외");
        } catch (Exception e) {
            System.out.println("에러 메시지 : " + e.getMessage());
            e.printStackTrace();
        }
    }
}
  • 실행 결과

throws

public static void main(String[] args) throws IOException { ... do something }
  • do something 부분 실행에 실패하면 caller에게 예외가 전달되고 caller가 예외를 처리한다
    → 메서드를 소환한 코드가 예외를 처리하게 된다.
  • 메서드를 사용할 때 발생할 수 있는 예외를 미리 명시하기
    → 사용자가 미리 예외를 인지하고 그에 대한 처리를 강제할 수 있다.

try/catch

try { // 예외를 처리하길 원하는 실행 코드 }

catch (e1) { // e1 예외가 발생할 경우에 실행될 코드 } 
catch (e2) { // e2 예외가 발생할 경우에 실행될 코드 } 

...
finally { // 예외 발생 여부와 상관없이 무조건 실행될 코드 }
  1. try{ ... }: 예외가 발생하면 catch블록에서 처리, 예외가 발생하지 않는다면 바로 finally블럭으로 이동
  2. catch (e1) { ... }
    • 적절한 catch블럭을 찾지 못하면 예외 처리 불가 -> 프로그램 강제 종료
    • 적절한 catch블럭을 찾으면 throw 문의 피연산자를 예외 객체의 형식 매개변수로 전달
  3. finally{ ... }: 모든 예외처리가 끝나면 finally블럭으로 이동
  • 다른 제어문과는 달리 예외 처리문은 중괄호({})를 생략할 수 없다.
  • 모든 예외 클래스는 Exception 클래스의 자손이므로, catch (Exception e)와 같이 선언해 놓으면 어떠한 종류의 예외가 발생하더라도 이 catch 블럭에 의해 처리된다.
  • try블럭 안에 return문이 있어서 try블럭을 벗어나더라도 finally블럭은 실행된다.
public static void main(String[] args) {

	BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

	try {
		StringTokenizer st = new StringTokenizer(br.readLine());
	} catch (IOException e) {
		e.printStackTrace(); // 참조변수 e를 통해, 생성된 IOException인스턴스에 접근
	}
}
  • try문 안의 내용 실행에 실패하면 caller에게 예외가 전달되는 것이 아니라 catch문을 통해 예외를 처리하게 된다.
  • e.printStackTrace(): 예외 발생 당시 호출스택(Call Stack)에 있었던 메서드의 정보와 예외 메시지를 화면에 출력한다.

getMessage(): 발생한 예외클래스의 인스턴스에 저장된 메시지를 얻을 수 있다.


예외 클래스(Exception class)

1. RuntimeException 클래스와 그 자손들

  • 프로그래머의 실수로 발생하는 예외
    • e.g. ArrayIndexOutOfBoundsException, NullPointerException, ClassCastException, ArithmeticException
  • 치명적인 예외 상황을 발생시키지 않는 예외들로 구성
  • unchecked 예외 → 컴파일 가능
  • try/catch문을 사용하기보다는 예외에 신경쓰며 프로그램 작성하기

2. 그 외의 Exception 클래스와 그 자손들

  • 사용자의 실수와 같은 외적인 요인에 의해 발생하는 예외
    • e.g. FileNotFoundException, ClassNotFoundException, DataFormatException
  • checked 예외 → 예외를 처리하지 않으면 컴파일 시 오류 발생
  • 아래의 코드는 readLine()에서 발생할 수 있는 IOException에 대한 예외를 처리해주지 않았으므로 컴파일 시 오류가 발생한다.
public class Main {
	public static void main(String[] args) {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 	
		StringTokenizer st = new StringTokenizer(br.readLine()); 
		... 
	}
}
  • throws IOException을 통해 예외를 처리해주거나 try/catch문을 통해 예외 처리를 해 주면 된다.

사용자 정의 예외 클래스를 만들 때 기존에는 Exception 클래스를 상속받아 checked 예외를 작성하곤 했지만, 요즘은 RuntimeException 클래스를 상속받아 선택적인 예외처리를 허용하는 방향으로 변화하고 있다.


예외 처리의 계층 관계

  • 부모 클래스를 상위 catch문에 배치하면 자식 클래스가 속한 catch문이 실행되지 않는다.
  • 따라서 자식 클래스의 예외만을 따로 처리하고 싶으면 자식 클래스 속한 catch문을 부모 클래스 위에 배치해야 한다.
try { System.out.write(list);} 
catch (Exception e) {e.printStackTrace();} 
catch (IOException e) {e.printStackTrace();}
  • 위의 코드에서 IOException은 Exception의 자식 클래스이므로 catch (IOException e)문은 영원히 실행되지 않는다.
  • 그러므로 IOExeption만을 처리하고 싶다면 아래 코드와 같이 catch (IOException e)을 위에 써주어야 한다.
try {
    System.out.write(list);
} catch (IOException e) {  
    e.printStackTrace();
} catch (Exception e) {
    e.printStackTrace();
}

Source

2개의 댓글

comment-user-thumbnail
2021년 1월 14일

ㅎㅎ 스크럼 시간에 예외처리 공부해봐야 겠다고 생각했는데 여기 잘 정리되어 있네요 감사합니다.

1개의 답글