티스토리 뷰
Item71에서는 필요 없는 Checked Exception 사용을 피하라 말한다
앞선 Item70에서 신나게 단점에 대해 얘기했으니 Checked Exception의 장점을 알아보고자 한다
다음 질문을 참고해 보자
Checked Exception의 장점을 물어봤고 그에 대한 첫 번째 답변이 흥미롭다
주요 골자로 자신은 Checked Exception이 좋고 이 것이 에러에 강한 프로그램을 만드는데 도움을 준다는 것이다
Checked Exception 혐오자라면 이게 무슨 말 같지 않은 소리인가 싶겠다
NullPointerException을 예로 들어보자, 실무에서 NPE를 안 겪어본 이가 흔치 않을 것이다
이를 해결하는데 kotlin 같이 언어 차원에서 null을 막아버리는 우아한 해법도 있지만
자바 같이 try-catch로 감싸거나 조건문으로 처리하는 터프(?)한 해법도 있다
여기서 잠깐 망상을 해보자
NPE를 유발할 수 있는 행위가 Checked Exception으로 처리된다면 어떻게 될까?
즉 원시 타입이 아닌 객체 타입을 인자로 받는 모든 메서드는 강제로 try-catch를 걸어야 한다면
코드 작성자 입장에서는 너무나 괴롭고 자바를 손절치고 싶겠지만 에러 처리를 해뒀다면 NPE는 터지지 않을 것이다
현실성 없는 예시지만 Checked Exception을 이렇게도 바라볼 수 있겠구나 하고 이해하면 되겠다
컴파일 타임에 예외 처리를 하게끔 하는 그 의도 자체는 숭고하다
볼 품 없는 try-catch와 강제적으로 처리해야 한다는 점이 열 뻗침 포인트일 것이다
자바로 작성된 수많은 코드가 있기에 홀라당 코틀린으로 넘어갈 수도 없는 노릇이다
이왕 이렇게 된 거 Checked Exception을 즐겨보자
자신의 프로젝트에 Exception을 상속받아 예외 처리를 하라는 말은 절대 아니다
책에서 나오는 스트림에서 직접 사용할 수 없다는 부분은 아래와 같은 꼼수로 처리가 가능하다
제네릭, 람다에 익숙하다면 금방 익힐 수 있을 것이다
다만 개인적인 감상으로는 이를 완전히 이해한 이가 아니고서야 스트림에서 try-catch 좀 줄여보겠다고
오히려 코드 복잡도를 늘리는 꼴이라 실무에 적용시키기 전에 반드시 팀원의 합의를 이끌어내야 할 필요가 있다
@FunctionalInterface
public interface SupplierExceptionWrapper<T, E extends Exception> {
static <T, E extends Exception> Supplier<T> toUnchecked(SupplierExceptionWrapper<T, E> f) {
return toUnchecked(f, e -> {
throw new RuntimeException(e);
});
}
static <T, E extends Exception> Supplier<T> toUnchecked(SupplierExceptionWrapper<T, E> f, Consumer<Exception> c) {
return () -> {
try {
return f.supply();
} catch (Exception e) {
c.accept(e);
return null;
}
};
}
T supply() throws E;
}
try-catch가 모든 코드에 박혀있는 게 싫다면 try-catch 안에서 실행시켜야 하는 로직 자체를 넘겨
마치 함수형인 듯 써보는 건 어떨까? 물론 난 사용하지 않는 방식이다, 그냥 재미로 만들어봤다
이 방식은 로직과 에러 처리를 분리할 수 있다는 점에 의의가 있을 것 같다, 잡기술이지만 SRP를 지켜내는 것 아닐까?
결론으로 생각의 전환을 해보면 다른 언어에는 Checked Exception이 없는 기능이니 자바에서만 신나게 쓸 수 있다는 것이다!
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class TryUtils {
public static <T> void doTry(Consumer<T> consumer, T parameter) {
try {
consumer.accept(parameter);
} catch (Exception e) {
log.error("Exception : ", e);
}
}
public static <T> Optional<T> doTry(Supplier<T> supplier) {
try {
return Optional.ofNullable(supplier.get());
} catch (Exception e) {
return Optional.empty();
}
}
}
'Java > Effective Java' 카테고리의 다른 글
[Item72] 표준을 사용하자 (0) | 2023.06.18 |
---|---|
[Item70] Checked Exception 금지 (0) | 2022.11.01 |
[Item69] 예외 기반 반복 (2) | 2022.09.25 |
[Item68] 컨벤션 따르기 (1) | 2022.09.11 |
[Item67] 최적화는 나중에 (0) | 2022.08.28 |