티스토리 뷰

스프링, 자바

자바 예외 처리

killog 2021. 1. 16. 15:39
반응형

목표

자바의 예외 처리에 대해 학습하세요.

학습할 것 (필수)

  • 자바에서 예외 처리 방법 (try, catch, throw, throws, finally)
  • 자바가 제공하는 예외 계층 구조
  • Exception과 Error의 차이는?
  • RuntimeException과 RE가 아닌 것의 차이는?
  • 커스텀한 예외 만드는 방법

 


참고문헌 보고 그린 예외처리 계층 구조도

 


 


자바에서 예외 처리 방법

try-catch

try{
    // 예외가 발생할 가능성이 있는 코드
   System.out.println(1 / 0);
}catch(IllegalArgumentException e){
    // IllegalArgumentException이 발생했을때, 이를 처리
     log.info(e.getClass().getName());
     log.info(e.getMessage());
}catch(ArithmeticException e){
    // ArithmeticException 이 발생했을때, 이를 처리
     log.info(e.getClass().getName());
     log.info(e.getMessage());
     
      logger.error(e.getMessage()); //e.printStackTrace

    /*
     예외 정보 Message, StackTrace 등 여러 정보를 얻어올 수 있다.
    */
}
/*
java.lang.ArithmeticException
/ by zero
*/

try 블럭에는 여러 개의 catch 블록이 올 수 있다.

  • 예외가 발생시 예외에 대한 인스턴스가 생성된다.
  • 이후, try 문을 실행하지 않고, 바로 catch 블록으로 이동한다.
  • catch 문들을 차례대로 살펴보면서, instance of연산자를 이용해 발생한 예외의 종류와 일치하는 단 한 개의 catch 블록을 찾는다.
  • 해당 catch 문을 수행한 뒤, try-catch문을 탈출한다.

throw

고의로 예외를 발생시킬 수 있는 키워드. 특정 예외에서 구체적 예외 처리 핸들링이 가능하다.

  try {
           if (password.equals("abc")) {
                    throw new IllegalArgumentException("too common password");
               /*
                   아래 코드와 같은 기능을 수행한다.
                   IllegalArgumentException e = new IllegalArgumentException("too common password");
                throw e;
               */
            }
       } catch (IllegalArgumentException e) {
            log.info(e.getMessage());
       }

throws

일종의 메소드 자체에 예외를 박는 방법이다. 즉, 예외가 발생한 메소드에서 명시한 예외로 예외 객체를 넘긴다.

  • 메소드를 읽기 간결하게 할 수 이따.
  • 또한, 메소드 이름 옆에 발생할 수 있는 명시적 예외 덕분에 코드 작성에 유의할 수 있어, 팀 프로젝트에 유용하다.
public class Test{
    static void callDriver() throws ClassNotFoundException{
        Class.forName("oracle.jdbc.driver.OracleDriver");
        System.out.println("완료");
    }

    public static void main(String[] args){
        try{
            callDriver();
        }catch(ClassNotFoundException e){
            System.out.println("클래스를 찾을 수 없습니다.");
        }finally{
            System.out.println("시스템 종료");
        }
    }

}

finally

finally 블럭은 예외와 상관없이 실행되는 블럭이다. 만약 try 블럭에서 예외가 발생하면 바로 catch 블럭을 찾기 때문에
꼭 필요한 코드가 실행되지 않을 수 있다. 이러한 경우에 finally를 사용 할 수 있다.

데이터 베이스나, 파일을 사용후, 닫는 기능이나, 자원을 명시적으로 반납해야하는 경우와 같이, 항상 수행할 필요가 있는 겨웅 사용한다.

catch 문의 예외 타입을 작성할 때는 항상 명확한 예외 타입을 작성하는 것을 우선으로 해야한다.

try {
       System.out.println(10 / 0);
} catch (Exception e) {
    e.printStackTrace();
} finally {
    log.info("function is ended");
}

[Java7] try - catch - resource

InputStream, 또는 네트웤프로그래밍에서 사용하는 Socket,ServerSocket 을 좀 더 안전하게 사용할 수 있도록 지원해준다.

자원 해제를 따로 안써도 된다는 장점이 있다. (메모리 누수의 원인)

 try(FileInputStream f = new FileInputStream("notExist.txt")){
   // try() Exception 발생시 바로 f.close() 메소드 실행하고 catch 로
   // 명시적으로 f.close() 를 적어주지 않는다.
   System.out.println(f.read());
 }catch(IOException e){
      e.printStackTrace();
 }

try(code)를 인식하여, close를 필요한 코드가 있으면, 바이트코드를 조작하여, close를 생성한다.

( 이 이전에는 , 이중 try 중첩문으로 close 를 수행했다.)

try-with-resource의 핵심은 AutoClosable의 인터페이스입니다. 이 인터페이스는 Closable의 부모 클래스이고, close메소드를 가지고 있습니다. 이 인터페이스를 통해 리소스는 try블록으로 스코프가 한정되고 올바른 순서로 자동으로 닫히게 됩니다.

예외 처리 정보 받기

catch 블록의 참조 변수를 통해 인스턴스에 접근 가능하다.

  • printStackTrace(): 예외 발생 당시의 호출스택에 있었던 메서드 정보와 예외 메시지를 화면에 출력한다.
  • getMessage(): 발생한 예외클래스의 인스턴스에 저장된 메시지를 얻을 수 있다.

다중 중첩 예외처리

  • JDK 1.7부터 여러 catch block을 하나로 합칠 수 있게 되었다.
  • | 연산자를 이용한다.
  • 나열된 예외 클래스들이 부모-자식 관계에 있다면 컴파일 에러가 발생한다.
  try {
            System.out.println(10 / 0);
      } catch (IllegalArgumentException | ArithmeticException e) {
      // catch(예외1 | 예외2 e)
                   e.printStackTrace();
                  log.info(e.getMessage());

      }

참조 변수 중복과 내부 중첩 예외처리

catch 블럭 안에 다시 try-catch 구문을 사용할 수 있다.

단, 참조변수 명이 중첩되어선 안된다.

   try {
            System.out.println(1 / 0);

        } catch (RuntimeException e) {
            try {
                methodB();
            } catch (IllegalArgumentException e) {   // 에러 발생: 해당 변수의 이름을 e로 할 수 없다.
                ...
            }
        }

예외 처리 전략

( https://blog.baesangwoo.dev/posts/java-livestudy-9week/#try-with-resources 이용했습니다.)

예외 복구

문제를 파악하고 해결해 정상 상태로 되돌리는 방법입니다. 어떤 예외가 발생시 다른 작업 흐름으로 자연스럽게 유도합니다. 가장 대표적으로 try/catch/finally 절을 사용할 수 있습니다.

private void printStr(String str) {
    try {
        System.out.println("str length : " + str.length());
    } catch (NullPointerException e) {
        System.out.println(-1);
    }
}

printStr("test"); // 4 (정상 케이스)
printStr(null); // -1 (예외 처리. 다른 작업 흐름으로 이어짐)

예외 처리 회피

예외처리 회피는 자신이 직접 예외처리 하지 않고, 호출하는 메소드를 전파시키는 방법입니다. throws 문으로 예외를 회피하는 방법과, catch블록으로 예외를 잡고, 로그를 남긴 후, throw 하는 방법이 있습니다.

// throws로 회피하기
public void process() throws SQLException {
    // jdbc 로직...
}

// catch 후 로그 남기고 다시 throw
public void process2() throws SQLException {
    try {
        // jdbc 로직...
    } catch (SQLException e) {
        System.out.println(e.getMessage())
        throw e;
    }
}

예외 전환

예외 전환은 예외 회피와 비슷하다고 볼 수 있지만 발생한 예외를 그대로 넘기지 않고 더 적절한 예외로 전환하여 던지는 특징이 있습니다.

내부에서 발생한 예외가 모호하여 의미가 명확한 예외를 던지기 위해 전환할 수 있습니다.

// 예외의 에러 코드에 따라 분기하여 예외 전환
public void add(User user) throws DuplicateUserIdException, SQLException {
    try {
        // code ..
    } catch (SQLException e) {
        if (e.getErrorCode() == MysqlErrorNumbers.ER_DUP_ENTRY) {
            throw new DuplicateUserIdException();
        }

        throw e;
    }
}

이렇게 예외를 전환할 때는 기존 예외를 담아서 중첩 예외로 만드는 것이 좋습니다.

catch (SQLException e) {
    throw new DuplicateUserIdException(e);
}

예외를 처리하기 쉽게 포장하기 위해 전환할 수 있습니다.

예를 들어 Checked Exception을 잡아서 Unchecked Exception으로 던져서 해당 메소드를 사용 하는 곳에서 일일히 에러 처리를 할 필요가 없습니다.

private void process() {
    try {
        // code ...
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

사용자 지정 예외 처리

모든 예외는 자바 문법에서 발생할 수있는 예외이다.

비즈니스 로직이나 업무 흐름과 관련된 예외를 만들어 개발자나 사용자가 정확한 문제를 파악하기 더 쉽습니다.기존 예외 집합의 특정 처리를 제공하기 위해서 커스텀 예외를 만들 수 있습니다.

// 커스텀한 Checked Exception
public class InvalidFileNameException extends Exception {
    public InvalidFileNameException(Throwable e) { // 예외 중첩을 사용하기 위한 생성자
        super(e);
    }
}

// 적용하기
private void processFile(String fileName) throws InvalidFileNameException, FileNotFoundException {
    try {
        new FileInputStream(fileName);
    } catch (FileNotFoundException e) {
        if (fileName.length() < 1) {
            throw new InvalidFileNameException(e); //사용자 지정 예외 처리
        }
        throw e;
    }
}

또한 예외 전환 뿐만 아니라 일반적인 비즈니스 로직에서 예외를 발생시키고 싶을 때도 사용이 가능합니다.

private void printFileName(String fileName) throws InvalidFileNameException {
    if (fileName.length() < 1) {
        throw new InvalidFileNameException(e);
    }

    System.out.println(fileName);
}


  • 자바가 제공하는 예외 계층 구조
  • Exception과 Error의 차이는?


참고 문헌

https://www.notion.so/cce3fc21976f4400aa4ed8d3fb26497b

https://blog.baesangwoo.dev/posts/java-livestudy-9week

https://velog.io/@youngerjesus/자바-예외-처리#2-자바가-제공하는-예외-계층-구조

https://github.com/kongduboo/whiteship-java-study/blob/main/week9.md

https://leegicheol.github.io/whiteship-live-study/whiteship-live-study-09-exception-handling/

https://www.notion.so/3565a9689f714638af34125cbb8abbe8

https://catch-me-java.tistory.com/46

https://sujl95.tistory.com/62

https://wisdom-and-record.tistory.com/46

https://i-am-clap.tistory.com/12

반응형

'스프링, 자바' 카테고리의 다른 글

[intelly j ] spring 초기 세팅 모음집  (0) 2021.01.18
자바의 스레드  (0) 2021.01.16
자바의 인터페이스  (0) 2021.01.03
7주차 과제: 패키지  (0) 2020.12.27
자바 상속  (2) 2020.12.26
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/05   »
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
글 보관함