hubring

[JAVA] Exception 처리 본문

Spring Boot

[JAVA] Exception 처리

Hubring 2020. 8. 31. 00:06

Exception 그저 try/catch로 처리해야거나 실행중 문제 발생했다고 빨간 글씨로 괴롭히는 놈으로만 인식했었는데....
생각해보니 잘모르고 사용하였기에 정리한다.

 

Exception 이란?

예외는 개발자가 구현한 로직안에서 발생하여,  예외는 발생할 상황을 미리 예측하여 개발자가 처리할 수 있다..

모든 예외 클래스는 그림과 같이 Throwable을 상속받고 있다.
참고로 Error 역시 Throwable을 상속받고 있는데 이는 시스템 레벨의 심각한 수준의 에러로 시스템에 변화를 주어 문제를 처리해야하는 경우가 일반적이다. (ex. JVM OOM)  반면 Exception은 개발자가 로직을 추가하여 처리할 수 있다.

 

 

Checked Exception/ Unchecked Exception

Exception을 상속받고 있는 Runtime Exceptions은  checked Exception과 unchecked Exception을 구분하는 기준이다.
Runtime Exception을 상속하고 있으면 unchecked Exception이고 아니라면 checked Exception이라 한다.

  Checked Exception  Unchecked Exception
처리여부 반드시 예외 처리 필요
(try/chatch 또는 throws로 넘겨서 처리)
명시적 처리를 강제 하지 않음
확인시점 컴파일 단계 런타임 단계
예외발생시 트랙잭션 처리 롤백 처리 하지 않음(반드시 처리해야 하므로) 롤백해야함.
대표 클래스 IOException, SQLException 등 NullPointerException, IndexOutOfBoundException 등

 

대표적인 예외 클래스들

  • NullPointerException : Null 레퍼런스를 참조할때 발생, 뭔가 동작시킬 때 발생한다.
  • (XXX)IndexOutOfBoundsException : 배열과 유사한 자료구조(문자열, 배열, 자료구조)에서 범위를 벗어난 인덱스 번호 사용으로 발생
  • (XXX)FormatException : 문자열, 숫자, 날짜 변환 시 잘못된 데이터(ex. "123A" -> 123 으로 변환 시)로 발생, 보통 사용자의 입력, 외부 데이터 로딩, 결과 데이터의 변환 처리에서 자주 발생한다.
  • ArthmeticException : 정수를 0으로 나눌때 발생
  • ClassCastException : 변환할 수 없는 타입으로 객체를 변환할 때 발생
  • IllegalArgumentException : 잘못된 인자 전달 시 발생
  • IOException : 입출력 동작 실패 또는 인터럽트 시 발생
  • IllegalStateException : 객체의 상태가 매소드 호출에는 부적절한 경우
  • ConcurrentModificationException : 금지된 곳에서 객체를 동시에 수정하는것이 감지될 경우 발생
  • UnsupportedOperationException : 객체가 메소드를 지원하지 않는 경우 발생

 

주요 메소드들

  • printStackTrace() : 발생한 Exception의 출처를 메모리상에서 추적하면서 결과를 알려준다. 발생한 위치를 정확히 출력해줘서 제일 많이 쓴다. void를 리턴한다.
  • getMessage() : 한줄로 요약된 메세지를 String으로 반환해준다.
  • getStackTrace() : jdk1.4 부터 지원, printStackTrace()를 보완, StackTraceElement[]이라는 문자열 배열로 변경해서 출력하고 저장한다.

 

예외처리 방법

1. try/catch 구문 이용한다 

try {
   // Protected code
} catch (ExceptionName e1) {
   // Catch block
}

 

Java7 이상 버전에서는 한 catch구문안에 여러 Exception을 같이 쓸 수 있다.

catch (IOException|FileNotFoundException ex) {
   logger.log(ex);
   throw ex;
   

 

2. throws/throw 구문을 이용하여 해당 메소드를 사용하고 있는 상위 메소드에게 처리를 넘긴다.

import java.io.*;
public class className {

   public void deposit(double amount) throws RemoteException {
      // Method implementation
      throw new RemoteException();
   }
   // Remainder of class definition
}

 

예외처리 후 로그 남기기

예외가 발생하면 이를 로그로 남겨 문제가 발생된 코드를 추적할 수 있게 해야한다.

 

다음과 같은 경우는 이전의 예외를 추적할 수 없는 로그로 흔히 개발자가 많이 하는 실수이다.

try {
  /* ... */
} catch (Exception e) {   // Noncompliant - exception is lost
  LOGGER.info("context");
}

try {
  /* ... */
} catch (Exception e) {  // Noncompliant - exception is lost (only message is preserved)
  LOGGER.info(e.getMessage());
}

try {
  /* ... */
} catch (Exception e) {  // Noncompliant - original exception is lost
  throw new RuntimeException("context");
}

 

예외를 추적이 가능한 로그는 아래와 같다.
이와 같이 로그를 작성하면 stack trace를 통해 예외가 발생한 코드를 추적할 수 있다.

try {
  /* ... */
} catch (Exception e) {
  LOGGER.info(e);  // exception is logged
}

try {
  /* ... */
} catch (Exception e) {
  throw new RuntimeException(e);   // exception stack trace is propagated
}

try {
  /* ... */
} catch (RuntimeException e) {
  doSomething();
  throw e;  // original exception passed forward
} catch (Exception e) {
  throw new RuntimeException(e);  // Conversion into unchecked exception is also allowed
}

 

 

Custom RuntimeException 만들기

필요에 따라 업무 처리를 위해 새로운 Exception을 만들어야하는 경우가 있다.

이 경우 Exception을 상속받은 클래스(ex DataAccessException)를 이용하여 아래와 같이 예외를 발생시킬 것이다.

public void update(String query) {
  try {
    // ...
  } catch (SQLException e) {
    throw new DataAccessException();
  }
}

하지만 이러한 코드는 위에서 언급했던 추적가능한 로그를 만들 수 없다.

 

따라서 이를 해결하는 방법으로 RuntimeException을 상속받아서 생성해 줄 때 Throwable 객체(RuntimeException 상위 클래스)를 생성자에 넣어줄 수 있다. 즉, catch한 exception을 생성자로 받아줄 수 있다. 

public RuntimeException(Throwable cause) {
        super(cause);
}

 

아래와 같이 받은 Exception 정보를  바로 생성자에 넘겨 줄 수 있다.

public void update(String query) {
  try {
    // ...
  } catch (SQLException e) {
    throw new DataAccessException(e);
  }
}

 

 

참고 : 

http://www.tutorialspoint.com/java/java_exceptions.htm

https://sjh836.tistory.com/122 [빨간색코딩]

https://velog.io/@codemcd/Java-Exception-%EC%B2%98%EB%A6%AC%ED%95%98%EA%B8%B0-w4k1yecz4f

'Spring Boot' 카테고리의 다른 글

직접 빌드하기  (0) 2020.08.04
Spring Boot Documentation  (0) 2020.08.04
IntelliJ Gradle 대신 자바 직접 실행  (0) 2020.08.04
Spring boot - Security  (0) 2020.07.23
Spring boot - properties 분리  (0) 2020.07.14