[JAVA] 예외 처리 (3)

DongGyu Jung·2022년 2월 6일
0

자바(JAVA)

목록 보기
22/60
post-thumbnail

🏃‍♂️ 들어가기 앞서..

본 게시물은 스터디 활동 중에 작성한 게시물로 자바의 정석-기초편 교재를 학습하여 정리하는 글입니다.
※ 스터디 Page : 〔투 비 마스터 : 자바〕

*해당 교재의 목차 순서와 구성을 참고하여 작성하며
각 내용마다 부족할 수 있는 내용이나 개인적으로 궁금한 점은
추가적인 검색을 통해 채워나갈 예정입니다.



📝 "사용자 정의" 예외

지난 글부터 다뤄봤을 때
Java에 Exception클래스가 있는 것을 알 수 있었는데
이 클래스를 활용해서

사용자가 직접 예외 클래스를 정의할 수 있다.
방법은
Exception클래스 ( 사용자 발생 필수처리 ) 나
RuntimeException클래스 ( 프로그래머 실수 발생
선택처리 ) 중
하나를 선택해서 상속시키면 된다.

class MyException extends Exception {
    MyException(String msg) { // 문자열을 매개변수로 받는 생성자
        super(msg); // 조상인 Exception클래스를 super() 조상 생성자로 호출
	}
}

조금 더 구체화 시켜본다면

class MyException extends Exception { // Exception 클래스는 try-catch 필수 처리
    private final int ERR_Code ; // (private 상수) 생성자를 통해 초기화
    
    MyException(String msg, int errCode) { // 문자열을 매개변수로 받는 생성자
        super(msg); // 조상인 Exception클래스를 super() 조상 생성자로 호출
		ERR_Code = errCode;
    }
    
    MyException(String msg) { // 생성자
        this(msg, 100); // ERR_Code를 기본값 100으로 초기화
    }
    
    public int getErrCode() { // 에러코드 얻는 메서드 추가
        // 메서지는 getMessage()를 통해 얻을 수 있기 때문에 별도로 할 필요 없음.
        return ERR_Code ;
    }
}

위 클래스를 통해
MyException이 발생했을 때,
catch블럭에서 getMessage()getErrCode()를 활용할 수 있다.
( try-catch문을 필수적으로 작성하는 Exception클래스를 활용해서 만들게되면 복잡해지기 때문에 RuntimeException을 주로 사용한다고 한다. )


💫 예외 되던지기 (exception re-throwing)

" 예외를 처리한 후 ", 다시 예외를 발생시키는 것

기껏 처리했는데 다시 발생시킨다니...
이게 무슨 헛소리인가 싶었지만

" 하나의 예외 "에 대해서
<예외가 발생한 메서드> 와 이를 <호출한 메서드>

" 양쪽 모두에서 처리해줘야 할 작업 이 있을 때 " 사용된다.
( 예외 처리한 것에 대한 추가적인 처리가 필요할 때 )

먼저
<예외가 발생할 가능성이 있는 메서드> 에서
try-catch문을 사용해서 예외를 처리해주고
catch문에서 필요한 작업을 행한 후

throw문을 사용해서 예외를 다시 발생시킨다.
이 재발생한 예외는
" 호출한 메서드 "에 전달되고
" 호출한 메서드의 try-catch "에서 또 예외를 처리하는 방식이다.

public static void main(String[] args) {
    try {
        method1();
    } catch (Exception e) {
        System.out.println("main메서드 예외 처리");
    }
}

static void method1() throws Exception { // throws로 예외 선언 필요
    try {
        throw new Exception();
    } catch (Exception e) {
        System.out.println("method1메서드 예외 처리");
        throw e; // 다시 예외 발생시켜서 main메서드로 예외 전달
    }    
}

위 코드에서 봤듯이
예외가 발생할 메서드에서
try-catch문을 사용해 예외 처리를 해줌과 동시에
" 메서드 선언부 "에
발생할 예외throws에 지정해주어야 한다.


🔗 연결된 예외 (chained exception)

" 한 예외가 다른 예외를 발생시킬 때의 인과관계 "

인과관계를 나타내고
서로 발생에 대한 연관성을 나타낼 수 있는데

예를 들어
예외 A가 " 예외 B를 발생시킨다. " 라면
예외 A는 " 예외 B의 원인예외(cause exception) "라고 칭한다.

  • Throwable initCause(Throwable cause) : 지정예외(Throwable cause)를 원인예외로 "등록"
  • Throwable getCause() : 원인예외를 "반환 "

( Throwable클래스 = Exception클래스 & Error클래스의 조상클래스 )

이렇게 관계를 정립시키는 이유는

여러가지 예외를
" 하나의 큰 분류의 예외로 묶어서(포함시켜) 다루기 " 위해서이다.

void install() throws InstallException { //아래처럼 발생한 예외를 포함시켜 다시 던지는 구조
  try {
      startInstall(); // SpaceException이 발생하게되면 첫번째 catch문으로 이동
      copyFiles();
  } catch (SpaceException se) { //예외 A
      InstallException ie = new InstallException("예외 발생") ; // 예외 생성 _ 예외B
      ie.initCasue(se) ; // InstallException의 "원인예외"로 SpaceException을 지정
      
      throw ie; // InstallException로서 발생시키기
      // SpaceException을 InstallException로 포함시켜
      // InstallException이 발생된 것으로 만듦
  } catch (MemoryException me) {
      ...
  }
}

위 메서드를 사용하게되면

try {
    install() ;
} catch (SpaceException e) {
    e.printStackTrace();
} catch (MemoryException e) {
    e.printStackTrace();
} catch (Exception e) {
    e.printStackTrace();
}

/*
위와같은 반복적인 catch를
아래처럼 큰 범위로 관리할 수 있다.
*/
try {
    install();
} catch(InstallException e) {
    e.printStackTrace();
} catch(Exception e) {
    e.printStackTrace();
}

checked예외를 " unchecked예외로 변경하려 할 때 사용

이미 알아봤지만
checked예외는 필수처리를 해야하기 때문에
강제로 복잡한 try-catch문이 작성될 수도 있는데
unchecked로 바꾸게 된다면
선택적으로 변경되는 것이다.

/*
이 SpaceException클래스는 Exception클래스를 상속받은 상태로 생성이 되기때문에
try-catch문의 굴레에서 벗어나기 힘든 상태이다
*/
class SpaceException extend Exception {
    SpaceException(String msg) {
        super(msg) ;
    }
}

/*
이때 연결된 예외를 활용하여
어떠한 checked 예외를
unchecked예외 클래스에 "포함" 시켜서
unchecked 예외클래스 중 하나인 것처럼 위장시켜서
처리문에서 자유롭게 만들어줄 수 있다.
*/
static void startInstall() throws SpaceException, MemoryException { //둘다 필수처리
    if (!enoughSpace())
        throw new SpaceException("설치 공간 부족") ;
    if (!enoughMemory())
        throw new MemoryException("메모리 부족") ;
}
/*
위 코드를 ↓
*/
static void startInstall() throws SpaceException { //MemoryException을 선택처리로 바꾸기 위해 제외
    if (!enoughSpace())
        throw new SpaceException("설치 공간 부족") ;
    if (!enoughMemory())
        // initCasue() 대신 RuntimeException 생성자에 작성함
        throw new RuntimeException(new MemoryException("메모리 부족")) ; //포함시키기
        // RuntimeException(Throwable cause) 방법으로도 원인예외로 등록 가능
        
        //MemoryException unchecked화
}

0개의 댓글