✔예외 처리(Exception Handling)
1. 에러(Error)와 예외(Exception)
- 에러와 예외 : 어떤 원인에 의해 오동작하거나 비정상적으로 종료되는 경우.
에러(Error)
: 메모리 부족, stack overflow와 같이 일단 발생하면 복구할 수 없는 상황. (심각도 높음)
- 프로그램의 비정상적 종료를 막을 수 없음. -> 디버깅 필요.
예외(Exception)
: 읽으려는 파일이 없거나 네트워크 연결이 안되는 경우 등 수습될 수 있는 비교적 상태가 약한 것들. (심각도 낮음)
예외 처리(Exception Handling)
: 예외 발생 시 프로그램의 비정상 종료를 막고 정상적인 실행 상태를 유지하는 것.
- try~catch~finally : 예외의 감지 및 예외 발생시 동작할 코드 작성
- 예외 클래스의 계층
- Checked Exception : 예외에 대한 대처 코드가 없으면 컴파일 진행 실패.
- Unchecked Exception(RuntimeException 하위 클래스) : 예외에 대한 대처 코드가 없더라도 컴파일 진행 성공. (하지만 실행시 예외가 발생하므로 try~catch 필요.)
2. 예외 처리(Exception Handling)
try ~ catch
: 예외 처리 기법
- 예외를 처리하여 프로그램이 정상적으로 동작하도록 하는 역할.
- 어떠한 예외도 발생하지 않는 경우 catch 블록을 거치지 않고 다음 문장 실행.
finally
: 예외 발생 여부와 상관없이 언제나 실행하는 블록
- 주요 목적 : try 블록에서 사용한 리소스 반납.(자원 정리를 위해 사용.)
- 생성한 시스템 자원을 반납하지 않으면 resource leak 발생 가능.(파일 입출력은 운영체제에서 관리.)
try{
}catch (XXException e){
}finally{
}
- Exception 객체의 정보 활용
- Throwable의 주요 메서드
- public String getMessage() : 발생된 예외에 대한 구체적인 메시지 반환.
- public Throwable getCause() : 예외의 원인이 되는 Throwable 객체 또는 null 반환.
- public void printStackTrace() : 예외가 발생된 메서드가 호출되기가지의 메서드 호출 스택 출력.
- 디버깅 수단으로 주로 사용.
- 프로그램 정보가 그대로 노출되므로 디버깅으로만 사용하고 실제 제품 배포때는 이 메서드를 막은 상태로 출시해야한다.
- 다중 Exception Handlig 기법
- 하나의 try 블록에 여러 개의 catch 블록 추가 가능.
- 다중 catch 문장 작성 순서 유의 사항 : 작은 범위(자식)에서 큰 범위(조상)순으로 정의.
- JVM이 던진 예외는 catch 문장을 찾을 때 다형성 적용.
- 상위 타입 예외가 먼저 선언되는 경우 뒤에 등장하는 catch 블록은 동작할 기회가 없음.
- Unreachable catch block for Exception
- 상속 관계가 없는 경우는 무관
- 발생하는 예외들을 하나로 처리하기 : Exception 사용.
- 예외 상황별 처리의 어려움.
- 가급적 예외 상황별로 처리하는 것 권장.
- 심각하지 않은 예외 세분화하여 처리하는 것도 낭비
- '|' 연산을 이용해 하나의 catch 구문에서 상속관계가 없는 여러 개의 exception 처리
- (ex) XXException | OOException e
- 계층을 이루는 예외의 처리 : 상속 관계를 고려하여 처리.
- try - with ~ resources : JDK 1.7 이상에서 리소스 자동 close 처리.
- 단, 해당 객체들이 AutoCloseable interface를 구현해야 한다.
- FileInputStream -> InputStream -> Closeable -> AutoCloseable
- 각종 I/O Stream, socket, connection, ...
- 해당 객체는 try 블록에서 다시 할당될 수 없다.
try(리소스_타입1 res1 = 초기화; 리소스_타입2 res2 = 초기화; ...){
}catch(Exception e){
}
2. throws
throws
키워드 : 처리해야할 예외 위임.
- method에서 처리해야 할 하나 이상의 예외를 호출한 곳으로 전달(처리 위임)
- 예외가 없어지는 것이 아니라 단순히 전달하는 것.
- 예외를 전달받음 메서드는 다시 예외 처리의 책임 발생.
- 처리하려는 예외의 조상 타입으로 throws 처리 가능.
- checked exception throws 처리 위임.
void testMethod() throws Exception1, Exception2{
}
void methodCaller(){
try{
testMethod();
}catch (Exception e){
}
}
- runtime exception(unchecked exception) throws 처리 위임.
void testMethod(){
}
void methodCaller(){
try{
testMethod();
}catch (Exception e){
}
}
- 로그 분석과 예외의 추적
- Throwable의 printStackTrace는 메서드 호출 스택 정보 조회 가능.
- 최초 호출 메서드에서부터 예외 발생 메서드까지 스택 정보 출력.
- 예외 종류, 예외 원인, 디버깅 출발점. 등 확인.
- 메서드 재정의와 throws
- 메서드 재정의시 조상 클래스 메서드가 던지는 예외보다 큰(조상) 예외를 던질 수 없다.
- 부모가 치지 않은 사고를 자식이 칠 수 없다.
✔사용자 정의 예외
사용자 정의 예외
: API에 정의된 exception 이외에 필요에 따라 사용자 정의 예외 클래스 작성
- 대부분 Exception 또는 RuntimeException 클래스 상속받아 작성.
- checked exception 활용 : 명시적 예외 처리 또는 throws 필요.(코드 복잡, but 처리 누락 등의 오류 가능성 저하)
- runtime exception 활용 : 묵시적 예외 처리 가능.(코드 간결, but 처리 누락 등의 오류 가능성 상승)
- 장점
- 객체의 활용 : 필요한 추가 정보, 기능 활용 가능.
- 코드의 재사용 : 동일한 상황에서 예외 객체 재사용 가능.
- throws 메커니즘 이용 : 중간 호출 단계에서 return 불필요.
- 시스템의 RuntimeException은 처리의 대상이기보다는 디버깅의 대상.