예외처리를 간소화하여, 코드를 이쁘게 해보자!
해당 포스팅에서 언급된 내용은 Ndroid 에서 제공합니다.
매일 코딩을 하던 중 같은 것을 반복한다고 느끼는 경우가 있습니다.
그 중 하나가 아마 예외처리를 하는 것이라 생각합니다.
예외처리는 개발자가 의도적으로 어떤상황이 일어났을 때의 상황을 처리 못하니, 위의 stack 에서 알아서 하라고 던지는(throw) 행위입니다. (사실 이 행위는 프로그램코드가 아닌 실세계에서도 많이 일어납니다. ㅡㅡ^)
일단 예외처리에 대한 제 입장은 이러한 예외처리를 꼼꼼하게 계속해야 한다고 생각합니다.
조금 회사에서 일을 해보니, 프로그램 작성 시에는 일부로 어떠한 경우들을 일부로 체크안해서 UnCheckException (꼭 처리를 안해도 되는 예외) 을 내보내도 되지 않을까(쉽게는 NullPointerException)생각하여 작성해보았는데 디버깅 시, 유지보수가 더 쉽지가 않음을 깨달았습니다.
로직의 스탭(모듈 등)간의 관계에 대하여 강결함(?) 보장이 의도적으로 되야 하는데, 의도적으로 예외를 내지 않아버리면 갑자기 어디선가 죽어버리는 녀석을 계속 찾아야하는 것 같습니다. (같은 NullPointer 에 대한 예외를 처리한다 하더라도, 아무것도 안하고 Runtime 중 일으키는 것보다는 의도적으로 RuntimeException 이라도 넘기는 것이 좋다고 생각합니다. 메시지도 같이 말이죠....)
어쨌든 이러한 처리를 아마 아래와 같이 코드를 작성하곤 합니다.
1 2 3 | if (a == null) { throw new MessageException("잘못된 접근입니다."); } | cs |
비지니스로직에 흔히 작성될 수 있는 코드입니다.
간단해보이지만 아래와 같이 체크해야할 경우가 많다면 어떨까요?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | if (a == null) { throw new MessageException("잘못된 접근입니다."); } if (list == null || list.isEmpty()) { throw new MessageException("잘못된 접근입니다."); } if (string == null || string.toString() == null || string.toString().isEmpty()) { throw new RuntimeException("잘못된 접근입니다."); } if (map == null || map.isEmpty()) { throw new MessageException("잘못된 접근입니다."); } if (!map.containsKey("a")){ throw new RuntimeException("잘못된 접근입니다."); } | cs |
뭔가 꼼꼼하긴 하지만, if 블럭 안에 예외 한개씩 입력하고 있는 공통점이 있어보입니다. 이러한 단순 작업을 요즘은 툴(인텔리J)이나 어노테이션(NonNull)등으로 어느정도 커버할 수 있지만, 안드로이드나 웹프로젝트에서 같이 작업하는 입장에서 생각할 때는 호스트코드에 작성하는 방식을 아에 무시할 수는 없어보입니다.
(잘 모르는 것일 수도 있습니다. ~ @.@ ~)
일단은 같이 일하는 선배님께서 이러한 부분을 간결하게 해보자는 것을 제안하셔서, 아래와 같은 코드를 한번 배포해 보았습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /** * 단순한 NullCheck 매크로 * * @param object * @param message */ public void NullCheck(Object object, String message) throws MessageException { if (object == null) { throw new MessageException(message); } } NullCheck(vo, "잘못된 접근입니다."); | cs |
MessageException은 CheckedException 종류로 컨트롤러로 이 예외가 던져진다면, 프론트에서 사용자가 메시지를 볼 수 있도록 합니다.
이 코드로 인하여, 예외를 처리하는 것은 매우 단순하게 간결 해졌습니다.
복잡한 방식을 간결하게 바꾸는 시도는 여러가지로 시도 되고 있고(인터페이스를 람다로 치환한다는 등..), 이러한 방식을 제안한 선배님께는 감사하고 있습니다.
단순하게 Null 뿐 아니라, string 빈 값, Container 의 빈 상태 등 자주 사용하는 여러 상황을 체크하는 메소드를 만들었고, 잘 사용하고 있었지만 이 코드에는 문제가 있음을 깨닫게 되었습니다.
간결 예외처리 코드는 아쉽게도 MessageException 밖에 출력을 못합니다.
경우에 따라서는 RuntimeException 을 내보내야할 때도 있으며, 안드로이드와 라이브러리를 공유한다고 했을 때 웹에서만 사용하는 MessageException 을 안고 갈 수는 없었습니다.
이를 해결하기 위해 예외의 형태를 제네릭으로 받아 동적으로 예외를 만들자는 생각이 들었습니다. 아래와 같은 초안 메소드를 작성하게 되었고, 오버로딩으로 간략하게 사용할 수 있는 메소드도 같이 제공하였습니다.
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 31 32 33 34 35 36 37 38 | /** * Check with CustomException. * * @param check * @param message * @param exceptionClass * @param <T> * @throws T */ public final static <T extends Exception> void Check( @NonNull Boolean check , @NonNull String message , @NonNull Class<T> exceptionClass) throws T{ if (!check) { final T exception; try { exception = exceptionClass.getConstructor(String.class).newInstance(message); } catch (Exception e) { throw new RuntimeException(e); } throw exception; } } /** * Check. * * @param check */ public final static void Check(@NonNull Boolean check) { Check(check, ERROR_BAD_ASSESS, RuntimeException.class); } Check(object != null, "[에러] object 는 Null 일 수 없음", RuntimeException.class); Check(object != null); | cs |
이러한 형태로 자주 사용하는 예외체크 타입을 간략화한 유틸클래스를 릴리즈하였으며, 사용은 아래와 같습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // Check CheckUtil.Check(object != null, "Occurred Error! Please ask administrator!", RuntimeException.class); // Null check CheckUtil.NullCheck(object, "Occurred Error! Please ask administrator!", MessageException.class); // String empty check. CheckUtil.EmptyToStringCheck(object); // Maybe Empty check. CheckUtil.EmptyMaybeCheck(MaybeUtil.JustNullable(object)); // Container Check. CheckUtil.EmptyContainerCheck(Collections.emptyList()); // Collection CheckUtil.EmptyContainerCheck("Test", "Test2"); // Array CheckUtil.EmptyContainerCheck(Collections.emptyMap()); // map | cs |
RxJava2 에서 제공하는 Maybe 개념까지 CheckUtil 에 넣게 되었습니다.
보다 자세한 내용은 아래 url 에서 확인하실 수 있습니다.
이 포스팅이 보다 간결한 코딩을 하는 것에 도움이 되길 바래요 ~ @.@ ~
'개발이야기 > 오픈소스 N series ' 카테고리의 다른 글
구간을 표현하자! [Between 기능 소개] (4) | 2017.07.06 |
---|---|
Calendar 를 조금 더 쉽게 써보자, TimeUtil & TimeBuilder (0) | 2017.03.26 |
RxJava2 의 Maybe를 조금 더 적극적으로 써보자! MaybeUtil! (2) | 2017.03.16 |
안드로이드 람다 조합 (RxJava2 호환) (0) | 2017.03.08 |
조금 더 구체적인 안드로이드 개발 패턴화 (2) | 2017.01.30 |