티스토리 뷰
CheckedException를 싫어하는 자바 프로그래머가 많지만 제대로 활용하면 API와 프로그램의 질을 높일 수 있습니다.
결과를 코드로 반환하거나 UnCheckedException를 던지는 것과 달리, CheckedException는 발생한 문제를 프로그래머가 처리하여 안전성을 높이게끔 해줍니다.
물론, CheckedException를 과하게 사용하면 오히려 쓰기 불편한 API가 됩니다.
어떤 메서드가 CheckedException를 던질 수 있다고 선언됐다면, 이를 호출하는 코드에서는 catch 블록을 두어 그 예외를 붙잡아 처리하거나 더 바깥으로 던져 문제를 전파해야만 합니다.
어느 쪽이든 API 사용자에게 부담을 줍니다.
더구나 CheckedException를 던지는 메서드는 스트림 안에서 직접 사용할 수 없기 때문에 자바 8부터는 부담이 더욱 커졌습니다.
API를 제대로 사용해도 발생할 수 있는 예외이거나, 프로그래머가 의미 있는 조치를 취할 수 있는 경우라면 이 정도 부담쯤은 받아들일 수 있을 것입니다.
그러나 둘 중 어디에도 해당하지 않는다면 UnCheckedException를 사용하는 게 좋습니다.
CheckedException와 UnCheckedException 중 어느 것을 선택해야 할지는 프로그래머가 그 예외를 어떻게 다룰지 생각해보면 알 수 있습니다.
다음과 같이 하는 게 최선일까 생각해봅시다.
} catch (TheCheckedExceptuon e) {
throw new AssertionError(); // 일어날 수 없다.
}
다음 방식도 생각해봅시다.
} catch (TheCheckedExceptuon e) {
e.printStackTrace();
System.exit(1);
}
더 나은 방법이 없다면 UnCheckedException를 선택해야 합니다.
CheckedException가 프로그래머에게 지우는 부담은 메서드가 단 하나의 CheckedException만 던질 때가 특히 큽니다.
이미 다른 CheckedException도 던지는 상황에서 또 다른 CheckedException를 추가하는 경우라면 기껏해야 catch 문 하나 추가하는 선에서 끝입니다.
하지만 CheckedException가 단 하나뿐이라면 오직 그 예외 때문에 API 사용자는 try 블록을 추가해야 하고 스트림에서 직접 사용하지 못하게 됩니다.
그러니 이런 상황이라면 CheckedException를 안 던지는 방법이 없는지 고민해볼 가치가 있습니다.
CheckedException를 회피하는 가장 쉬운 방법은 적절한 결과 타입을 담은 옵셔널을 반환하는 것입니다. (아이템 55)
CheckedException를 던지는 대신 단순히 빈 옵셔널을 반환하면 됩니다.
이 방식의 단점이라면 예외가 발생한 이유를 알려주는 부가 정보를 담을 수 없다는 것입니다.
반면, 예외를 사용하면 구체적인 예외 타입과 그 타입이 제공하는 메서드들을 활용해 부가 정보를 제공할 수 있습니다. (아이템 70)
또 다른 방법으로, 검사 예외를 던지는 메서드를 2개로 쪼개 비검사 예외로 바꿀 수 있습니다.
이 방식에서 첫 번째 메서드는 예외가 던져질지 여부를 boolean 값으로 반환합니다.
try {
obj.action(args);
} catch (TheCheckedException e) {
... // 예외 상황에 대처한다.
}
리팩터링하면 다음처럼 됩니다.
if (obj.actionPermitted(args)) {
obj.action(args);
} else {
... // 예외 상황에 대처한다.
}
이 리팩터링을 모든 상황에 적용할 수는 없습니다.
그래도 적용할 수만 있다면 더 쓰기 편한 API를 제공할 수 있습니다.
리팩터링 후의 API가 딱히 더 아름답진 않지만, 더 유연한 것은 확실합니다.
프로그래머가 이 메서드가 성공하리라는 걸 안다거나, 실패 시 스레드를 중단하길 원한다면 다음처럼 한 줄로 작성해도 무방합니다.
obj.action(args);
이 한 줄짜리 호출 방식이 주로 쓰일 거로 판단되면 리팩터링하는 편이 바람직합니다.
한편, actionPermitted는 상태 검사 메서드에 해당하므로 아이템 69에서 말한 단점도 그대로 적용되니 주의해야 합니다.
즉, 외부 동기화 없이 여러 스레드가 동시에 접근할 수 있거나 외부 요인에 의해 상태가 변할 수 있다면 이 리팩터링은 적절하지 않습니다.
actionPermitted와 action 호출 사이에 객체의 상태가 변할 수 있기 때문입니다.
또한 actionPermitted가 action 메서드의 작업 일부를 중복 수행한다면 성능에서 손해이니, 역시 이 리팩터링이 적절하지 않을 수 있습니다.
정리
- 꼭 필요한 곳에만 사용한다면 CheckedException는 프로그램의 안전성을 높여주지만, 남용하면 쓰기 고통스러운 API를 낳는다.
- API 호출자가 예외 상황에서 복구할 방법이 없다면 UnCheckedException를 던지자.
- 복구가 가능하고 호출자가 그 처리를 해주길 바란다면, 우선 옵셔널을 반환해도 될지 고민하자.
- 옵셔널만으로는 상황을 처리하기에 충분한 정보를 제공할 수 없을 때만 CheckedException를 던지자.
'JAVA > 이펙티브 자바' 카테고리의 다른 글
아이템[73]. 추상화 수준에 맞는 예외를 던져라 (0) | 2022.05.22 |
---|---|
아이템[72]. 표준 예외를 사용하라 (0) | 2022.05.19 |
아이템[70]. 복구할 수 있는 상황에는 CheckedException를, 프로그래밍 오류에는 런타임 예외를 사용하라 (0) | 2022.05.19 |
아이템[69]. 예외는 진짜 예외 상황에만 사용하라 (0) | 2022.05.19 |
아이템[68]. 일반적으로 통용되는 명명 규칙을 따르라 (0) | 2022.05.19 |
- Total
- Today
- Yesterday
- 알고리즘
- 프로그래머스
- AWS
- MSA
- JPA
- Spring Boot
- 이펙티브 자바
- 정규표현식
- 테라폼
- kkoon9
- node.js
- C++
- Java
- kotest
- Spring
- 클린 코드
- 이팩티브 자바
- Kotlin
- Olympiad
- programmers
- BAEKJOON
- Effective Java
- Algorithm
- 코테
- 클린 아키텍처
- BOJ
- 객체지향
- 백준
- 디자인 패턴
- 디자인패턴
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |