1. 예외 처리의 두 가지 방법
: main과 method()가 호출 스택에 있다고 가정하자.
(1) main에서 호출한 method()에서 try-catch문으로 예외 처리하기.
(2) main에서 호출한 method()에서 예외가 발생되어, main으로 넘겨서 try-cathc문으로 처리하기.
2. finally 블럭
- finally 블럭은 try-catch문과 함께 예외의 발생여부에 상관없이 실행되어야 할 코드를 포함시킬
목적으로 사용된다.
- 순서는 다음과 같다
(1) try -> catch -> finally
(2) try -> finally
- finally는 try에서도 꼭 실행되어야 되는 구문과 catch에서도 꼭 실행되어야 되는 구문을 넣어야 할 때
활용된다.
3. 이해를 돕기 위한 예제(1)
: 2번 내용을 이해하기 위한 예제이다.
( 중간에 try 도중 return; 사용하여 다시 main으로 돌아가는데 finally가 먼저 실행이 되었다. )
4. 자동 자원 반환 - try - with - resources 문
- 이 구문은 입출력(I/O)과 관련된 클래스를 사용할 때 유용하다.
- 입출력(I/O) 때 FileInputStream 클래스 등 많이 사용할 것인데, 대부분 사용 후
꼭 close() 메서드를 사용하여 자원을 반납을 위해 닫아줘야 한다.
- 그러나 close() 메서드에서도 예외가 발생할 수 있으므로, try-catch문으로 써 주면
아래의 코드처럼 생성될 것이다.
( 이렇게 되면 너무 복잡하고, 별로 좋지 않다. )
( 그래서 등장하게 된 것이 try-with-resources이다. )
( 이 구문을 사용한다면, 에외가 발생하더라도 자원을 자동으로 반납할 수 있다. )
( 아래의 코드를 보자. )
( try의 괄호 안에 넣어서 객체를 생성하게 되면, try을 벗어나는 순간 자동으로 close()를 수행하게 해준다. )
( 이렇게 해줄려면, AutoCloseable 인터페이스를 구현되어야 한다. )
( 그러나 이렇게 하더라도 close에서 예외가 발생할 수 있다. )
( 아래의 예제를 통해 확인해보자. )
5. 이해를 돕기 위한 예제(2)
: 4번 내용을 이해하기 위한 예제이다.
( 첫 번째 try-catch 문에서는 close()만 호출했다. )
( 두 번째 try-catch 문에서는 exception()과 close()를 호출했는데, 먼저 WorkException에 대한 예외가
나오고, 그 다음으로 CloseException에 대한 예외가 나오는데 억제된(Suppressed)이 머리말과 함께
출력되었다.)
( 억제된 이유는 동시에 예외가 발생할 수는 없기 때문이다. )
( 그래서 억제된 예외에 대한 정보는 WorkException에 저장된다. )
6. 사용자 정의 예외 만들기
- 보통은 아래의 코드처럼 만든다.
- 또한 아래의 코드처럼 멤버를 추가해서 다양하게 메시지를 전달할 수 있다.
7. 이해를 돕기 위한 예제(3)
: 6번 내용을 응용한 예제이다.
( 하나의 catch가 잡힌다면, 뒤에 catch문은 무시하고 정상적으로 프로그램을 종료시킨다. )
8. 예외 되던지기(exception re-throwing)
- 호출한 메서드에서 try-catch문과 호출된 메서드에서 try-catch문을 양 쪽 모두에서
실행되도록 하기 위해서 예외 되던지기를 한다.
- 방법은 간단하다. 아래의 코드를 보자.
- 또한 아래의 코드처럼 return문이 있는 경우도 사용된다.
( 만약 return문이 catch 안에 없다면, 오류가 난다. )
( 또한 catch는 return문 대신 예외 던지기도 가능하다. )
( 만약 fianlly에 return100이 활성화 된다면, 출력문은 100이 나온다. )
9. 연결된 예외(chained exception)
- 예를 들어, 예외 A가 예외 B를 발생시켰다면, A를 B의 '원인 예외"라고 한다.
- 아래의 코드는 예외를 catch를 통해 등록하고 있다.
( 위 코드를 보면 발생한 예외를 바로 처리하지 않고 예외를 initCause() 메서드를 통해 SpaceException을
InstallException의 원인 예외로 등록하여 다시 예외를 발생시키고 있다. )
( *initCause()는 Exception 클래스의 조상인 Throwable 클래스에 정의되어 있기 때문에 모든 예외에서
사용가능하다. )
( 또한 getCause()도 정의되어 있으며, 원인 예외를 반환한다. )
( 이렇게 하는 이유는 여러가지 예외를 하나의 큰 분류의 예외로 묶어서 다루기 위해서이다. )
( 아래의 코드를 보자. )
( 현재 SpaceException과 MemoryException 클래스가 InstallException을 상속받고 있다. )
( 이렇게 작성하게 되면 실제로 어떤 예외가 발생했는지 알 수 없다는 문제가 발생한다. )
( 또한 상속관계를 변경해야 한다는 것도 부담이 될 수 있다. )
( 그래서 생각한 것이 예외가 원인 예외를 포함시킬 수 있게 한 것이다. )
( 그렇게 되면 굳이 상속관계가 될 필요가 없다. )
- 또한 다른 이유로는 연결된 예외는 checked 예외를 unchecked 예외로 바꿀 수 있도록 하기 위해서이다.
( 위 아래의 코드를 비교해보자. )
( RuntimeException으로 변경해줌으로써, uncheked로 변경되었다. )
( 그러므로, throws에서 MomoryException을 쓸 필요가 없어졌다. )
( 이때, RuntimeException(Throwable cause)의 형태로 받아서 위에서 initCause()대신 사용했다. )
10. 이해를 돕기 위한 예제(4)
: 예외처리(1) + 예외처리(2)의 통합 예제이다.
public class Exercise001 {
public static void main(String[] args) {
try {
install();
} catch(InstallException e) {
e.printStackTrace();
} catch(Exception e) {
e.printStackTrace();
}
}
static void install() throws InstallException {
try {
startInstall(); // 프로그램 설치에 필요한 준비를 한다.
copyFiles(); // 파일들을 복사한다.
} catch (SpaceException e) {
InstallException ie = new InstallException("설치중 예외발생");
ie.initCause(e);
throw ie;
} catch (MemoryException me) {
InstallException ie = new InstallException("설치중 예외발생");
ie.initCause(me);
throw ie;
} finally {
deleteTempFiles(); // 프로그램 설치에 사용된 임시파일들을 삭제한다.
} // try의 끝
}
static void startInstall() throws SpaceException, MemoryException {
if(!enoughSpace()) { // 충분한 설치 공간이 없으면...
throw new SpaceException("설치할 공간이 부족합니다.");
}
if (!enoughMemory()) { // 충분한 메모리가 없으면...
throw new MemoryException("메모리가 부족합니다.");
// throw new RuntimeException(new MemoryException("메모리가 부족합니다."));
}
} // startInstall메서드의 끝
static void copyFiles() { /* 파일들을 복사하는 코드를 적는다. */ }
static void deleteTempFiles() { /* 임시파일들을 삭제하는 코드를 적는다.*/}
static boolean enoughSpace() {
// 설치하는데 필요한 공간이 있는지 확인하는 코드를 적는다.
return false;
}
static boolean enoughMemory() {
// 설치하는데 필요한 메모리공간이 있는지 확인하는 코드를 적는다.
return true;
}
} // ExceptionTest클래스의 끝
class InstallException extends Exception {
InstallException(String msg) {
super(msg);
}
}
class SpaceException extends Exception {
SpaceException(String msg) {
super(msg);
}
}
class MemoryException extends Exception {
MemoryException(String msg) {
super(msg);
}
}
( initCause()를 사용해서 InstallException의 상속관계를 없애고, 포함시킬 수 있다.)
( 또한 checked 예외를 unchecked로 변경시키면, 아래의 코드처럼 변경하면 된다. )
'자바 > 기본적인 개념' 카테고리의 다른 글
예외처리(1) (0) | 2021.12.16 |
---|---|
익명 클래스(anonymous class) (0) | 2021.12.16 |
내부 클래스(inner class) (0) | 2021.12.10 |
인터페이스의 default & static 메서드 (0) | 2021.12.09 |
인터페이스 다형성 (0) | 2021.12.08 |