7장. 오류 처리

[CleanCode] 7장 - Error Handling

Overview

*프로그램이 잘못될 가능성은 늘 존재한다. 그 원인은 **Error(오류)*이다.

  • 김모씨의 말을 빌리자면,,

Untitled

Error & Exception in Runtime

  • Error (오류)

    • 시스템이 종료되어야 할 수준의 심각한 상황 (프로세스 종료)

    • 미리 예측하여 방지 불가

    • ex) OutOfMemoryError, StackOverflowError

  • Exception (예외)

    • 개발자가 구현한 로직에서 발생하거나 사용자에 의해 발생

    • 개발자가 미리 방지 가능

상황에 맞는 Exception Handle을 해야한다.

Untitled

Exception Class

  • Throwable

    • Error / Exception에 대한 메세지를 담고, Chained Exception에 대한 정보들을 기록

      The Throwable class is the superclass of all errors and exceptions in the Java language. Only objects that are instances of this class (or one of its subclasses) are thrown by the Java Virtual Machine or can be thrown by the Java throw statement. Similarly, only this class or one of its subclasses can be the argument type in a catch clause. For the purposes of compile-time checking of exceptions, Throwable and any subclass of Throwable that is not also a subclass of either [RuntimeException](https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/lang/RuntimeException.html) or [Error](https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/lang/Error.html) are regarded as checked exceptions …

    • Throwable(String message, Throwable cause)

  • Java

  • Kotlin

  • 호출한 곳에 Exception 발생 여부 통보


오류 코드보다 예외를 사용하기

🌱 로직과 Exception 처리를 분리하기

  • 로직과 오류 처리 코드가 뒤섞여 있다.

  • 오류를 발견하면 예외를 던진다.


Try-Catch-Finally

  • try-catch-finally

  • 숫자를 0으로 나누면,,

  • 예외 처리

  • 예외가 발생하더라도 반드시 실행되어야 한다면,,

  • [Q] try-catch와 return 값

    • 어떤 구문에 있는 값이 반환될까?

    • return 값을 조작?

    • 메모리에 직접 접근한다면

    finally 에서의 리턴은 자제하자

  1. 파일이 없으면 예외를 던지는지 알아보는 단위 테스트

  1. 아래 코드는 테스트가 성공할까?

  1. Exception을 던지자

  1. 예외 유형을 좁히자

  • ex)

  • runCatching

  • kotilnx.runCatching

  • Exception은 크게 3가지 형태로 처리 가능

    • 회피 : 호출한 쪽으로 그대로 전달 (throw)

    • 복구 : 복구 또는 무시 가능한 경우에 catch 블럭 내에서 처리하거나 예외상황 처리후 에러 코드 반환

    • 전환 : 특정 Exception으로 변환하여 전달 (throw)


Unchecked Exception을 사용하기

Untitled
  • CheckedException

    • 단순 예외, 즉 컴파일 시 발생하는 Exception

    • 프로그램 작성 시 이미 예측 가능

    • 반드시 예외처리 해야함

  • UnCheckedException

    • 프로그램 실행시 발생하는 Runtime Exception

    • 명시적 처리를 요구하지 X

RuntimeException을 상속받는 Exception → Unchecked Exception

  • Kotlin의 모든 Exception은 Runtime Exception을 상속받는다.

  • UnCheckedException을 사용해보자

  • Checked Exception을 사용해보면?

    • 컴파일 오류

    • 예측 가능한 CheckedException → 예외처리 강제

  • 컴파일 오류를 막기위한 예외 처리

  • sayNickname 메서드에서 예외 발생 & 예외 처리 모두 하는 것?

    • sayNickname을 호출한 곳에서 예외 처리를 한다면? ✨

  • sayNickname에서 예외 처리 vs main에서 예외처리

  • Exception을 처리하는 위치는 중요하다.

in Clean Code,,

  • Checked Exception은 비용이 있다!

🌱 Checked Exception은 **OCP(Open-Closed Principle)를 위반한다.**

  • 단순 출력 로직

  • 출력을 안하는 Exception을 던질 때

    • 하위 단계 코드 변경 → 상위 단계 코드 변경

      • 모두 catch 블록에서 처리

      • 선언부에 throws 절 추가

🌱 Checked Exception은 **캡슐화를 깰 수 있다.**


Exception에 의미를 제공하기

🌱 오류가 발생한 **원인과 위치**를 찾을 수 있어야 한다.

  • stacktrace 활용

  • message에 유의미한 정보를 담아서 던지기

    • 실패한 연산 이름, 실패 유형 언급

  • Logging 가능 → catch 블록에서 오류 기록


Exception Class 정의하기

  • 호출자(Caller)를 고려해서 Exception을 정의할 수 있다.


정상 흐름을 정의하기

  • 총계를 계산하는 로직

    • 식비를 비용으로 청구 → 청구한 식비를 더함

    • 청구 X → 일일 기본 식비를 더함

  • 특수한 Exception이 있을 상황이 아니다.

  • DAO를 수정 → 항상 MealExpense 객체를 반환

  • Special Case Pattern (특수 사례 패턴)

    • 클래스 or 객체를 조작해서 특수한 사례를 처리

    • 클래스 내에서 예외적인 상황을 캡슐화


Null을 반환하지도, 전달하지도 마라

  • Null 반환

    • null 반환 대신 예외를 던지기

    • 특수 Wrapper 객체로 감싸서 반환

  • 직원 리스트를 가져와서 총 급여를 구하는 로직

  • null 반환 대신 빈 리스트를 반환하기

  • Null 전달

메서드가 null을 반환하는 방식도 나쁘지만, 메서드에 null을 전달하는건 더 나쁘다.

  • 두 지점 사이의 거리를 구하는 메서드

  • 인수로 null을 전달하면?

  • 예외를 만들어 던지기

    • Exception을 잡아내는 처리기가 필요

  • assert

    • 여전히 오류 발생

🌱 *애초에 null을 넘기지 못하게 하라*


결론

  • 명시적 Exception은 반드시 이름을 지정하여 catching

  • 어플리케이션에서 구현한 함수 내에서 Exception 발생이 예상되는 경우

    • 최상위 Exception 클래스에서 반드시 catch 처리

    • Exception을 처리하는 궁극적인 위치가 중요.

  • Exception 발생시에는 Crashlytics 와 같은 에러 로그 라이브러리 등을 이용하여 개발자가 인지할 수 있도록 하기

Last updated