1. Exception Handling
에러와 예외
어떤 원인에 의해 오동작 하거나 비정상적으로 종료되는 경우
심각도에 따른 분류
Error
- 메모리 부족, stack overflow와 같이 일단 발생하면 복구할 수 없는 상황
- 프로그램의 비 정상적 종료를 막을 수 없음 → 디버깅 필요
Exception
- 읽으려는 파일이 없거나 네트워크 연결이 안되는 등 수습될 수 있는 비교적 상태가 약한 것들
- 프로그램 코드에 의해 수습될 수 있는 상황
exception handling(예외 처리)란
예외 발생시 프로그램의 비 정삭적 종료를 막고 정상적인 실행 상태를 유지하는 것
예외 클래스의 계층
checked exception
예외에 대한 대처 코드가 없으면 컴파일이 진행되지 않음
unchecked exception (RuntimeException의 하위클래스)
예외에 대한 대체 코드가 없더라도 컴파일은 진행됨
try ~ catch 구문
public static void main(String args[]) {
int [] intArray = { 10 };
try {
// 예외가 발생할 수 있는 코드
System.out.println(intArray[2]);
} catch (ArrayIndexOutOfBoundsException e) { // 던진 예외를 받음
// 예외가 발생했을 때 처리할 코드
System.out.println("예외가 발생했지만 처리함: 배열 크기 확인 필요");
}
System.out.println("프로그램을 종료합니다.");
}
Exception 객체의 정보 활용
Throwable의 주요 메서드
메서드 | 설명 |
---|---|
public String getMessage() | 발생된 예외에 대한 구체적인 메시지를 반환한다. |
public Throwable getCause() | 예외의 원인이 되는 Throwable 객체 또는 null을 반환한다 |
public void printStackTrace() | 예외가 발생된 메서드가 호출되기까지의 메서드 호출 스택을 출력한다. 디버깅의 수단으로 주로 사용된다. |
try-catch 문에서의 흐름
try 블록에서 예외가 발생하면
JVM이 해당 Exception 클래스의 객체 생성 후 던짐
- throw new XXException()
던져진 exception을 처리할 수 있는 catch 블록에서 받은 후 처리
- 적당한 catch 블록을 만나지 못하면 예외처리 실패
정상적으로 처리되면 try-catch 블록을 벗어나 다음 문장 진행
try 블록에서 어떠한 예외도 발생하지 않은 경우
catch문을 거치지 않고 try-catch 블록의 다음 흐름 문장을 실행
다중 exception handling
try 블록에서 여러 종류의 예외가 발생할 경우
하나의 try 블록에 여러 개의 catch블록 추가 가능
try {
//exception이 발생할 만한 코드
} catch (XXException e) {
// XXException 예외처리
} catch (YYException e) {
// YYException 예외처리
} catch (Exception e) {
// Exception 예외처리
}
유의사항
JVM이 던진 예외는 catch문장을 찾을 때는 다형성이 적용됨
상위타입의 예외가 먼저 선언되는 경우 뒤에 등장하는 catch 블록은 동작할 기회가 없음
상속관계가 없는 경우는 무관
상속관계에서는 작은 범위에서 큰 범위 순으로 정의
다중 예외 처리를 이용한 Checked Exception 처리
처리하지 않으면 컴파일 불가 : Checked Exception
예외 처리는 가능한 구체적으로 진행
발생하는 예외들을 하나로 처리하기
try {
// 다중 예외 발생 코드
} catch (Exception e) {
System.out.printf("예외 발생: %s%n",e.getMessage());
}
예외 상황 별 처리가 쉽지 않음
가급적 예외 상황 별로 처리하는 것을 권장
심각하지 않은 예외를 굳이 세분화 해서 처리하는 것도 낭비
'|'를 이용해 하나의 catch 구문에서 상속관계가 없는 여러 개의 exception 처리
try ~ catch ~finally 구문을 이용한 예외 처리
finally는 예외 발생 여부와 상관 없이 항상 실행
주요 목적: try 블록에서 사용한 리소스 반납
생성한 시스템 자원을 반납하지 않으면 장래 resource leak 발생 가능 → close 처리
try ~ with ~ resources
JDK 1.7 이상에서 리소스의 자동 close 처리
throws 키워드를 통한 처리 위임
method에서 처리해야 할 하나 이상의 예외를 호출한 곳으로 전달
- 예외가 없어지는 것이 아니라 단순히 전달됨
- 예외를 전달받은 메서드는 다시 예외 처리의 책임 발생
- 처리하려는 예외의 조상 타입으로 throws처리 가능
checked exception과 throws
checked exception은 반드시 try~catch 또는 throws 필요
필요한 곳에서 try~catch 처리
runtime exception과 throws
runtime exception은 throws 하지 않아도 전달되지만
하지만 결국은 try~catch로 처리해야함
로그 분석과 예외의 추적
Throwable의 printStackTrace()는 메서드 호출 스택 정보 조회 가능
최초 호출 메서드에서부터 예외 발생 메서드 까지의 스택 정보 출력
꼭 확인해야할 정보
어떤 예외인가? - 예외종류
예외 객체의 메세지는 무엇인가? - 예외 원인
어디서 발생했는가? - 디버깅 출발점
- 직접 작성한 코드를 디버깅 대상으로 삼을 것
- 참조하는 라이브러리는 과감히 건너뛰기
throws의 목적과 API 활용
API가 제공하는 많은 메서드들은 사전에 예외가 발생할 수 있음을 선언부에 명시하고 프로그래머가 그 예외에 대처하도록 강요함
메서드 재정의와 throws
메서드 재정의 시 조상클래스 메서드가 던지는 예외보다 부모예외를 던질 수 없다.
사용자 정의 예외
API에 정의된 exception이외에 필요에 따라 사용자 정의 예외 클래스 작성
대부분 Exception 또는 RuntimeException 클래스를 상속받아 작성
checked exception 활용 : 명시적 예외 처리 또는 throws 필요
- 코드는 복잡해지지만 처리 누락 등 오류 발생 가능성은 줄어듦
runtime exception 활용 : 묵시적 예외처리 가능
- 코드가 간결해지지만 예외 처리 누락 가능성 발생
사용자 정의 예외를 만들어 처리하는 장점
- 객체의 활용 - 필요한 추가정보, 기능 활용 가능
- 코드의 재사용 - 동일한 상황에서 예외 객체 재사용 가능
- throws 메커니즘의 이용 - 중간 호출 단계에서 return 불필요