📌 검사 예외의 장단점
🟡 pros
- 발생한 문제를 프로그래머가 처리하도록 강제하므로 안정성을 높인다.
- 구체적인 예외 타입과 그 타입이 제공하는 메서드들을 활용해 부가 정보를 제공할 수 있다.
🟡 cons
- 과하게 사용하면 쓰기 불편한 API가 된다.
- 호출자가 반드시 catch 블록을 두어 예외를 붙잡아 처리하거나, 바깥으로 던져야 하므로 사용자에게 부담을 준다.
- 검사 예외를 던지는 메서드는 스트림 안에서 직접 사용이 불가능하다.
- 단 하나의 검사 예외만 던질 때 가장 큰 부담을 준다.
- 다른 검사 예외도 던지는 상황이면 catch문 하나 추가하는 정도
- 검사 예외가 하나뿐이라면, 오직 그 예외 때문에 사용자는 try 블록을 추가하고 Stream을 사용할 수 없게 된다.
📌 검사 예외를 사용하는 경우
} catch (TheCheckedException e) {
throw new AssertionError(); // 일어날 수 없다!
}
} catch (TheCheckedException e) {
e.printStackTrace();
System.exit(1);
}
- 아래 두 경우를 제외하고는 비검사 예외를 고려하라
- API를 제대로 사용해도 예외가 발생할 수 있는 경우엔 검사 예외가 낫다.
- 프로그래머가 의미 있는 조치를 취할 수 있는 경우라면 이 정도 부담은 받아들일 수 있을 것이다.
- 프로그래머가 예외를 어떻게 다룰지 생각해보고, 위의 두 예시보다 나은 방법이 없다면 비검사 예외를 선택하라
📌 검사 예외 회피
1️⃣ Optional
public class FileReadExample {
public static Optional<String> readFileContents(String filePath) {
try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line).append(System.lineSeparator());
}
return Optional.of(sb.toString());
} catch (IOException e) {
// 파일 읽기 실패 시에는 예외를 무시하고 빈 옵셔널을 반환한다.
return Optional.empty();
}
}
public static void main(String[] args) {
String filePath = "example.txt";
Optional<String> contents = readFileContents(filePath);
if (contents.isPresent()) {
System.out.println("파일 내용: " + contents.get());
} else {
System.out.println("파일을 읽을 수 없습니다.");
}
}
}
- 검사 예외를 던지는 대신 단순히 빈 Optional을 반환한다.
- 예외가 발생한 이유를 알려주는 부가 정보를 담을 수 없다는 단점이 있다.
2️⃣ N개의 비검사 예외로 치환
// 검사 예외를 던지는 메서드 - 리팩터링 전
try {
obj.action(args);
} catch (TheCheckedException e) {
...
}
// 상태 검사 메서드와 비검사 예외를 던지는 메서드 - 리팩터링 후
if (obj.actionPermitted(args)) {
obj.action(args);
} else {
...
}
- 예외가 던져질지 여부를 boolean으로 반환한다.
- 리팩터링 후의 API는 다소 문제점이 있다.
- 유연성은 높지만, 딱히 더 아름답지는 않다.
- actionPermitted() 메서드는 상태 검사 메서드에 해당하므로 Item 69의 단점이 그대로 적용된다.
- 외부 동기화 없이 여러 스레드 동시 접근이 가능하거나, 외부 요인에 의해 상태가 바뀔 수 있는 경우를 주의하라.
- actionPermitted()와 action() 사이에 객체 상태가 변할 수 있다
- actionPermitted가 action 메서드 작업 일부를 중복 수행하면 성능 저하가 발생할 수 있다.
obj.action(args);
프로그래머가 이 메서드가 반드시 성공한다는 걸 알거나, 실패 시 Thread를 중단하길 원한다면 한 줄로 작성해도 무방하다.