ysk(0soo)
Lifealong
ysk(0soo)
전체 방문자
오늘
어제
  • 분류 전체보기 (238)
    • Java (50)
      • whiteship-java-study (11)
      • Java (28)
      • time (6)
    • Spring (68)
      • JPA (15)
      • Spring (1)
      • SpringBoot (1)
      • SpringMVC (6)
      • Spring Security (22)
      • Jdbc (1)
      • RestDocs (14)
      • log (6)
    • Kotlin (3)
    • Web (2)
      • nginx (1)
    • Database (14)
      • MySQL (5)
      • PostgreSQL (1)
      • SQL (1)
      • Redis (4)
    • C, C++ (0)
    • Git (1)
    • Docker (2)
    • Cloud (3)
      • AWS (3)
    • 도서, 강의 (0)
      • t5 (0)
    • 기타 (7)
      • 프로그래밍 (1)
    • 끄적끄적 (0)
    • CS (14)
      • 운영체제(OS) (2)
      • 자료구조(Data Structure) (9)
    • 하루한개 (12)
      • 우아한 테크코스-10분테코톡 (12)
    • 스터디 (12)
      • 클린 아키텍처- 로버트마틴 (2)
      • JPA 프로그래밍 스터디 (10)
    • 테스트 (34)
      • JUnit (19)
      • nGrinder (2)
      • JMeter (0)
    • Infra (3)
    • 프로그래머스 백엔드 데브코스 3기 (0)
    • 디자인 패턴 (3)
    • Issue (4)
    • system (1)
      • grafana (0)
      • Prometheus (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록
  • github

공지사항

인기 글

태그

  • AccessDecisionVoter 커스텀
  • junit5
  • nginx basic auth
  • AuthenticationException
  • tree
  • querydsl
  • FilterSecurityInterceptor
  • nGrinder
  • 트랜잭션
  • restdocs custom
  • 동일성
  • restdocs enum
  • jpa
  • 가상 스레드
  • 동등성
  • 동시성 제어
  • 구조화된 동시성
  • 가상 스레드 예외 핸들링
  • mysql
  • StructuredConcorrency
  • scope value
  • java
  • UserDetailsService
  • VirtualThread Springboot
  • DataJpaTest
  • LocalDateTime
  • 인가(Authorization) 처리
  • node exporter basic auth
  • AccessDecisionManager
  • 정규표현식

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
ysk(0soo)

Lifealong

Java/Java

예외 처리 방법(Exception Handling) - 복구, 회피, 전환

2022. 12. 7. 13:43

예외 처리 방법(Exception Handling)

예외를 처리하는 방법에는 예외 복구, 예외 처리 회피, 예외 전환 방법이 있다.

 

예외 복구

  • 예외 상황을 파악하고 문제를 해결해서 정상 상태로 돌려놓는 방법
  • 예외를 잡아서 일정 시간, 조건만큼 대기하고 다시 재시도를 반복한다.
  • 최대 재시도 횟수를 넘기게 되는 경우 예외를 발생시킨다.
final int MAX_RETRY = 100;
public Object someMethod() {
    int maxRetry = MAX_RETRY;
    while(maxRetry > 0) {
        try {
            ...
        } catch(SomeException e) {
            // 로그 출력. 정해진 시간만큼 대기한다.
        } finally {
            // 리소스 반납 및 정리 작업
        }
    }
    // 최대 재시도 횟수를 넘기면 직접 예외를 발생시킨다.
    throw new RetryFailedException();
}

예외복구는 예외가 발생하더라도 어플리케이션의 로직은 정상적으로 실행이 되게 하도록 처리한다는 의미 .

예외가 발생하면 일정 시간동안 대기를 시킨 후 다시 해당 로직을 재시도.

일정 횟수동안 재시도를 이런식으로 진행하며, 그래도 정상적인 응답이 오지 않는 경우 fail 처리하는 로직을 생각할 수 있다.

대부분의 상황에서 예외를 복구할 수 있는 경우는 거의 없기 때문에 자주 사용되지 않는다.

 

예외 처리 회피

  • 예외 처리를 직접 담당하지 않고 호출한 쪽으로 던져 회피하는 방법
  • 그래도 예외 처리의 필요성이 있다면 어느 정도는 처리하고 던지는 것이 좋다.
  • 긴밀하게 역할을 분담하고 있는 관계가 아니라면 예외를 그냥 던지는 것은 무책임하다.
// 예시 1
public void add() throws SQLException {
    // ...생략
}

// 예시 2 
public void add() throws SQLException {
    try {
        // ... 생략
    } catch(SQLException e) {
        // 로그를 출력하고 다시 날린다!
        throw e;
    }
}

예외 되던지기 - re-throwing

  • 한 메서드에서 발생할 수 있는 예외가 여럿인 경우 몇 개는 try-catch문을 통해서 메서드 내에서 자체적으로 처리
  • 나머지는 선언부에 지정하여 호출한 메서드에서 처리하도록 함으로써 양쪽에서 나눠서 처리되도록 함
  • 단 하나의 예외에 대해서도 예외가 발생한 메서드와 호출한 메서드 양쪽에서 처리하도록 할 수 있다.
    • 예외를 처리한 후에 인위적으로 다시 발생시키는 방법
void someMethod() throws Exception; // 선언부에 예외 지정
// 다음과 같이도 가능

void someMethod() throws Exception1, Exception2;

 

예외를 처리한 후에 인위적으로 다시 발생시키는 방법

public void someMethod() throws Exception {
  try {
    callMethod();
  } catch (Exception e) {
    System.out.prinltln(e.getName() + "예외 처리");
    throw e;
  }

} 

반환값이 있는 return 문의 경우 try블럭과 catch블럭에서 에외를 처리하고도 return 해야 한다.

public int someMethod() throws Exception {
  try {
    return callMethod();

  } catch (Exception e) {
    System.out.prinltln(e.getName() + "예외 처리");
    return -1; // 또는
    // throw new Exception(); // 대신 예외를 호출한 메서드로 전달
  }
} 
  • finally 문이 잇따면, 최종적으로 finally 블럭 내의 return문 값이 반환된다.

 

예외 전환

  • 예외 회피와 비슷하게 메서드 밖으로 예외를 던지지만, 그냥 던지지 않고 적절한 예외로 전환해서 넘기는 방법
  • 조금 더 명확한 의미로 전달되기 위해 적합한 의미를 가진 예외로 변경한다.
  • 예외 처리를 단순하게 만들기 위해 포장(wrap) 할 수도 있다.
  • 또한 Checked Exception이 발생했을 경우 이를 Unchecked Exception으로 전환하여 호출한 메서드에서 예외처리를 일일이 선언하지 않아도 되도록 처리할 수 도 있다.
// 조금 더 명확한 예외로 던진다.
public void add(User user) throws DuplicateUserIdException, SQLException {
    try {
        // ...생략
    } catch(SQLException e) {
        if(e.getErrorCode() == MysqlErrorNumbers.ER_DUP_ENTRY) {
            throw DuplicateUserIdException();
        }
        else throw e;
    }
}

// 예외를 단순하게 포장한다.
public void someMethod() {
    try {
        // ...생략
    }
    catch(NamingException ne) {
        throw new EJBException(ne);
        }
    catch(SQLException se) {
        throw new EJBException(se);
        }
    catch(RemoteException re) {
        throw new EJBException(re);
        }
}

즉 , 예외 전환이란 발생한 예외에 대해서 또 다른 예외로 변경하여 던지는 것

 

연결된 예외 (chained exception) : 어떤 예외를 다른 예외로 감싸는 것

  • 발생한 예외에 대해서 또 다른 예외로 변경할 때 사용한다 .
  • 언제 사용?
  1. 세부적인 사항을 포괄적인 사항으로 포함시킬 때 사용
  2. cheked 예외를 unchecked 예외로 변경시 사용(try-catch문 사용을 줄일 수 있음)
  • 한 예외가 다른 예외를 발생시킬 수 있다.
  • 예외 A가 예외 B를 발생시키면, A는 B의 원인 예외(cause exception)

다음 예는 SpaceException을 원인 예외로 하는 InstallException을 발생시키는 예제이다.

  • SpaceException이 InstallException 발생시킨다.
try {
    startInstall();
    copyFiles();
} catch (SpaceException e) {
    InstallException ie = new InstallException("설치중 예외발생"); // 예외 생성
    ie.initCause(e); // InstallException의 원인 예외를 SpaceException으로 지정
    throw ie; // InstallException을 발생시킨다.
} catch (MemoryException me) {
    ...
}
  • ie.initCause(e) : InstallException의 발생 원인을 SpaceException로 지정

Throwable initCause(Throwable cause)

  • 지정한 예외(cause)를 원인 예외로 등록
  • Exception클래스의 조상인 Throwable클래스에 정의되어 있기 때문에 모든 예외에서 사용이 가능

Throwable getCause()

  • 원인 예외를 반환

 

발생한 예외를 그냥 처리하면 될 텐데, 왜 원인 예외로 등록해서 다시 예외를 발생시킬까?

1. 큰 분류의 예외로 묶어서 다루기 위함

2. 상속관계를 무시할 수 있음

3. checked 예외를 unchecked 예외로 바꿀 수 있다

try {
    startInstall(); // SpaceException 발생
    copyFiles();
} catch (InstallException e) { // InstallException은
    e.printStackTrace(); // SpaceException과 MemoryExcpetion의 조상
}

위와 같이 InstallException을 SpaceException과 MemoryException의 조상으로 해서 catch 블럭을 작성하면, 실제로 발생한 예외가 어떤 것인지 알 수 없다는 문제가 있다.

  • SpaceException과 MemoryException의 상속관계를 변경해야 한다는 것도 부담이다.
  • 만약 원인 예외를 포함하게 된다면 두 예외는 상속관계가 아니여도 상관없다.

checked 예외를 unchecked 예외로 바꿀 수 있다.

static void startInstall() throws SpaceException, MemoryException {
    if (!enoughSpace()) // 충분한 설치 공간이 없으면
        throw new SpaceException("설치할 공간이 부족합니다.");
    if (!enoughMemory()) // 충분한 메모리가 없으면
        throw new MemoryException("메모리가 부족합니다."); 
}

static void startInstall() throws SpaceException {
    if (!enoughSpace()) // 충분한 설치 공간이 없으면
        throw new SpaceException("설치할 공간이 부족합니다.");
    if (!enoughMemory()) // 충분한 메모리가 없으면
        throw new RuntimeException(new MemoryException("메모리가 부족합니다.")); 
}

MemoryException은 Exception의 자손이므로 반드시 예외를 처리해야하는데, 이 예외를 RuntimeException으로 포장했기 때문에 unchecked 예외가 되었다.

  • 그래서 startInstall()의 선언부에 MemoryException을 선언하지 않아도 된다.

RuntimeException 생성자에는 원인 예외를 등록하는 생성자가 존재한다

RuntimeException(Throwable cause);

 

  • checked 예외를 unchecked 예외로 바꾸면 예외처리가 선택적이 되므로 억지로 예외처리 하지 않아도 된다.

 

정리

  • 예외 복구 전략이 명확하고 복구가 가능하면 Checked Exception을 try-catch로 예외 복구를 하거나, 코드의 흐름을 제어하는 것이 좋다.
  • 또한 Checked Exception이 발생했을 경우 이를 Unchecked Exception으로 전환하여 호출한 메서드에서 예외처리를 일일이 선언하지 않아도 되도록 처리할 수 도 있다.
    • 더 구체적인 UnChecked Exception을 발생시키고 예외에 대한 메시지를 명확하게 전달하는 것이 효과적이다.
  • 무책임하게 상위 메서드에 throw로 예외를 던지는 행위를 하지 않는 것이 좋다.
    • 상위 메서드들의 책임이 그만큼 증가하기 때문이다.
  • Checked Exception은 기본 트랜잭션 속성에서 Rollback을 진행하지 않는다.

참조

  • https://madplay.github.io/post/java-checked-unchecked-exceptions
  • https://steady-coding.tistory.com/m/583
  • 자바의 정석
저작자표시 비영리 (새창열림)

'Java > Java' 카테고리의 다른 글

Java 형식화 클래스 - Format, DecimalFormat, SimpleDateFormat  (0) 2022.12.08
Java UUID (+ IN MySQL )  (0) 2022.12.07
예외 처리란  (0) 2022.11.27
자바가 제공하는 기본 예외들과 자주 사용하는 예외들  (0) 2022.11.27
객체지향 관점에서의 is-a, has-a  (0) 2022.11.25
    'Java/Java' 카테고리의 다른 글
    • Java 형식화 클래스 - Format, DecimalFormat, SimpleDateFormat
    • Java UUID (+ IN MySQL )
    • 예외 처리란
    • 자바가 제공하는 기본 예외들과 자주 사용하는 예외들
    ysk(0soo)
    ysk(0soo)
    백엔드 개발을 좋아합니다. java kotlin spring, infra 에 관심이 많습니다. email : kim206gh@naver.com github : https://github.com/devysk

    티스토리툴바