일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- bit manipulation
- 코딩테스트
- geometry
- two pointers
- 코테
- Binary Search
- Counting
- array
- SQL
- greedy
- Matrix
- database
- Data Structure
- Stack
- dynamic programming
- Binary Tree
- Method
- Number Theory
- Math
- implement
- string
- hash table
- 구현
- Tree
- 파이썬
- sorting
- simulation
- java
- Class
- 자바
- Today
- Total
코린이의 소소한 공부노트
연결된 예외 본문
프로그램을 실행하는 과정에서 발생하는 미약한 오류를 예외라고 한다.
1. 예외는 사용자의 실수 등 프로그램 외적인 요소에 의해 발생하는 것으로, try-catch문을 이용해 발생한 예외를 처리한다.
2. 한 예외가 다른 예외를 발생시킬 수 있다. 예외 A가 예외 B를 발생시키면 A는 B의 원인 예외(cause exception)가 된다.
Throwable initCause(Throwable A) // A를 원인 예외로 등록
Throwable getCause() // 원인 예외를 반환
// Throwable 클래스 코드 살펴보기
public class Throwable implements Serializable{
// ...
// 원인 예외를 저장하기 위한 iv
private Throwable cause = this; // 객체 자신을 원인 예외로 등록(초기화)
// ...
public synchronized Throwable initCause(Throwable cause){
// ...
this.cause = cause; // 매개변수 cause를 원인 예외로 등록
return this;
}
// ...
}
1) Throwable은 Exception과 Error의 조상이다.
2) iv로 예외를 저장함으로써 예외 안에 또 다른 예외를 포함시키는 것이 연결된 예외인 것이다.
사용 예시를 들어보겠다. 아래 코드는 컴퓨터에 프로그램을 설치하는 과정에서 저장공간이 부족하게 됐을 때 원인 예외를 등록하는 과정을 나타낸 것이다.
void install() throws InstallException{
try{
startInstall(); // 저장 공간 부족 -> SpaceException 발생
copyFiles();
} catch(SpaceException e){ // e: 예외 A
InstallException ie = new InstallException("설치 중 예외 발생"); // ie: 예외 B
ie.initCause(e); // InstallException의 원인 예외로 SpaceException 지정
throw ie; // InstallException 발생시킴
} catch(MemoryException me){
// ...
}
1) 메서드 선언부에는 InstallException(IE)이 선언되어있다.
2) 메서드 실행 중 저장 공간이 부족해서 SpaceException(SE)가 발생하였다.
3) catch문에서 IE 객체를 생성하고, 해당 객체에 SE를 원인 예외로 지정했다.
4) IE를 발생시켰다.
이렇게 하면 실제로 발생한 예외는 SE지만, SE를 IE에 포함(연결)시킨 후 throw로 IE 객체를 던졌기 때문에 install() 메서드에서 발생한 예외는 IE가 되는 것이다. 그래서 메서드 선언부에 SE를 쓴 것이 아닌 IE를 쓴 것이다.
다소 복잡해 보이는데, 연결된 예외를 쓰는 이유는 무엇일까?
1. 여러 예외를 하나로 묶어서 다루기 위해
프로그램 설치 중 저장 공간이 부족, 메모리 부족 등 여러 예외가 발생할 수 있다. 예외 1개당 catch 블록을 1개씩 다 쓴다면, install() 메서드를 쓸 때마다 그 많은 catch 블록을 다 써야 한다. 연결된 예외를 쓰면 코드를 보다 간단하게 정리할 수 있다.
// 1) 연결된 예외 사용 전
try{
install();
} catch(SpaceException e){
e.printStackTrace();
} catch(MemoryException e){
e.printStackTrace();
} catch( // ...
// 2) 연결된 예외 사용 후
try{
install();
} catch(InstallException e){ // IE의 원인 예외로 SE, ME 등록
e.printStackTrace();
} catch( // ...
// 사라진 SE, ME catch 블록을 install() 안에 넣어줘야한다.
void install() throws InstallException{ // IE 예외 선언
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;
}
// ...
}
위 코드에서는 실제로 발생한 SE, ME를 처리한 것이 아니라 예외를 연결해주기만 한 것이다. ie를 처리하는 부분은 다른 곳에 만들어줘야 한다.
이렇게 예외를 묶어서 다룰 경우 예외가 발생했을 때 나오는 메시지도 묶기 전과 다르다. 보다 정확한 예외 정보를 얻을 수 있다.
// 1) 연결 전 - 세부 정보 파악 불가
MemoryException: 메모리 공간이 부족합니다. // 설치, 실행 중 언제 발생했는지 알 수 없음
at Test.install(Test.java:22)
at Test.main(Test.java:4)
// 2) 연결 후 - 대략적인 정보 + 세부 정보 파악 가능
InstallException: 설치 중 예외발생 // 발생 예외. 설치시 발생했다는 것을 파악할 수 있음
at Test.install(Test.java:17)
at Test.main(Test.java:4)
Caused by: MemoryException: 메모리 공간이 부족합니다. // 원인 예외
at Test.startInstall(Test.java:31)
at Test.install(Test.java:14)
... 1 more
2. checked 예외를 unchecked 예외로 바꾸기 위해서 - 필수 처리를 선택 처리로 변경
필수 처리 예외가 많으면 try-catch문을 다 써야 하기 때문에 코드가 너무 길어져 불편해진다. 그리고 굳이 필수 처리를 하지 않아도 되는 것도 있는데 체크드 예외이기 때문에 무조건 try-catch를 써야 하는 경우도 생긴다. 이러한 불편함을 처리하기 위해 연결된 예외를 쓴다.
static void startInstall() throws SpaceException, MemoryException{
if(!enoughSpace())
throw new SpaceException("설치 공간 부족");
if(!enoughMemory())
throw new MemoryException("메모리 부족");
}
1) startInstall() 메서드에 SE와 ME가 선언되어있다.
- 이 두 예외는 체크드 예외(Exception 클래스의 자손)이다.
- 언체크드 예외(RuntimeException 클래스의 자손)는 굳이 선언하지 않는다.
2) 체크드 예외를 언체크드로 바꾸려면 클래스 선언부를 변경해야 한다.
class MemoryException extends Exception{
// ...
- Exception을 RuntimeException로 바꾸면 언체크드 예외가 된다.
- 하지만 ME는 이미 여러 곳에서 많이 쓰이기 때문에 변경할 수 없다.
3) 클래스 선언부 변경 없이 체크드를 언체크드로 바꾸려면 연결된 예외를 이용하면 된다.
static void startInstall() throws SpaceException { // 변경부분 1
if(!enoughSpace())
throw new SpaceException("설치 공간 부족");
if(!enoughMemory())
throw new RuntimeException(new MemoryException("메모리 부족")); // 변경부분 2
}
- ME가 원인 예외가 되어 RuntimeException을 일으킨다. -> ME가 선택 처리 예외가 되었다.
- RuntimeException은 메서드에 예외 선언을 할 필요가 없다. -> 메서드 선언부에 SE만 선언한다.
'Java' 카테고리의 다른 글
String 클래스 (0) | 2022.08.16 |
---|---|
Object 클래스와 메서드 (0) | 2022.06.16 |
사용자 정의 예외 만들기, 예외 되던지기 (0) | 2022.05.27 |
예외 처리 (2) - 메서드에 예외 선언하기, finally 블록 (0) | 2022.05.26 |
예외의 분류 - 컴파일러 기준 (0) | 2022.05.25 |