본문 바로가기

JAVA,JSP

예외처리(2)

사용자 정의 예외

앞서 언급했던 NullPointerException, ArithmeticException 등의 경우, 

실행 시 문제가 되므로 자바 가상머신에서 예외로 정의해놓았습니다. 미리 정의된 예외들이죠.

하지만 이 외에도 개발자가 직접 예외를 정의하는 방법도 있습니다.


예를 들어 비즈니스 로직에서의 예외가 있을 수 있습니다.

입/출금 관련 프로그램이 있다고 가정했을 때 잔고보다 많은 돈을 출금하려는 경우 자바 프로그램 상에서는 전혀 문제가

안되지만, 입/출금 관련 업무에서는 예외 상황이 됩니다.

현실에선 마이너스 잔고라는게 없기 때문입니다. (마이너스 통장 말고 일반 통장 기준입니다..ㅋㅋ)

이럴 경우는 개발자가 직접 예외를 정의해줘야 합니다.


위의 상황을 간단하게 정의해보겠습니다.


일단 사용자 정의 예외를 만들어줍니다. 예외 클래스가 되는 조건은 아래와 같습니다.

Exception 클래스를 상속한다

Exception은 예외 클래스의 상위 클래스입니다. 따라서 이를 상속함으로써 해당 클래스는 예외 클래스가 되고,

try ~ catch 구문에 활용이 가능한 예외 클래스가 됩니다.


먼저 위의 상황에 맞는 예외 클래스를 하나 만들어보겠습니다.

public class NoMoneyException extends Exception{
    public NoMoneyException(){
        super("돈이 없습니다..");
    }
}

별다른 처리 없이 간단히 문자열을 출력하게 하였습니다. 

Exception 클래스를 상속하였으므로, 모든 예외처리 문법에서 사용 가능합니다.


static int totalMoney = 100000;

static int withdraw(int money) throws NoMoneyException{
    if(money > totalMoney){  // 예외 상황 발생시
        throw new NoMoneyException();  // 예외 발생!
    }else{
        totalMoney -= money;
    }
    
    return totalMoney;
}

전달받은 돈이 전체 돈보다 작을 경우는 위에서 우리가 언급한 예외 상황이 됩니다.

그리고 해당 예외 상황이 발생했을 경우, throw 구문을 사용하여 예외를 발생시킵니다.

(new로 해당 예외를 생성하는 순간 해당 메서드에 예외가 발생된 것이기 때문에 해당 메서드에 예외 처리 구문이 필요합니다.

위와 같이 throws를 통해 호출한 곳으로 던져줘도 되고, 해당 메서드에서 직접 처리해도 됩니다.)


main에서 예외상황을 발생시켜 보겠습니다.

static int totalMoney = 100000;

public static void main(String[] args){
    try{
        System.out.println(withdraw(10000000));
    } catch(NoMoneyException e){
        e.printStackTrace();
    }
}

잔고는 10만원인데 1000만원 인출을 시도하고 있습니다.. 대단한..

가슴 아픈 예외가 발생했네요..

보다시피 상황에 맞춰 정의했던 예외가 발생하고 있음을 보실 수 있습니다!



체크 예외, 언체크 예외

우리가 마주하는 일반적인 예외인 Exception 하위 예외들은 그 사이에서도 2가지로 종류가 나뉩니다.

체크 예외와 언체크 예외 라는 이름으로 나뉩니다. 이는 문법적으로도 차이가 있으니 알고 가시는게 좋습니다.


일단 해당 예외를 나누는 기준은, RuntimeException 이라는 예외의 상속 여부입니다.

Exception의 하위 예외이면서 RumtimeException을 상속하지 않았을 경우 체크 예외,

RumtimeException을 상속했을 경우 언체크 예외입니다.

(RumtimeException은 Exception의 서브 클래스이므로, 상속하면 자동으로 Exception의 하위 예외가 됩니다.)


1) 체크 예외

RumtimeException을 상속하지 않은 일반적인 예외들입니다. 반드시 try ~ catch나 throws를 통해 처리를 해줘야 하기 때문에

체크 예외라고 부릅니다. 항상 문법적으로 체크한다 라는 의미로 보시면 좋을 것 같습니다.

예를 들면 IOException, SQLException 등이 있습니다.


public static void main(String[] args){
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    
    try{
        System.out.println(br.readLine());
    } catch(IOException e){
        System.out.println("IOException 발생");
    }
}

앞서 작성했던 예외처리와 별 다를것 없어 보이지만, 이를 직접 IDE에서 코딩해보시면 차이를 느끼실 수 있습니다.

IOException은 체크 예외이므로 위와 같은 try ~ catch 구문이나, throws 구문이 없으면 컴파일 오류가 발생합니다.

프로그램상에서 반드시 이 예외를 처리하고 넘어가도록 강조하는 것입니다.

만약 throws를 통해 체크 예외를 던져줬다면, 호출하는 쪽에서도 해당 예외를 처리하는 구문을 필수로 입력해야 합니다.

throw를 통해 체크 예외를 발생시킬 경우도 마찬가지입니다. 처리가 없을 경우 컴파일 오류가 발생합니다.


2) 언체크 예외

RumtimeException을 상속한 예외입니다. 체크 예외처럼 해당 예외에 대한 처리를 문법적으로 강요하지 않기 때문에

언체크 예외라고 부릅니다. 개발자가 부주의할 경우 발생할 수 있는 예외들이라, 예상하지 못한 상황에 발생할 수 있는

그런 예외들이 아니므로 명시적인 처리를 강요하지 않은 것입니다.

예를 들면 NullPointerException, IllegalStatementException 등이 있습니다. 대부분의 예외가 런타임 예외입니다.


public static void main(String[] args){
    String str = null;
    System.out.println(str.length());
}

보다시피 해당 예외는 null값 참조로 인한 NullPointerException이 발생하는 코드입니다.

하지만 NullPointerException은 언체크 예외이므로 위의 코드는 컴파일 오류가 발생하지 않습니다.

throws를 통해 예외를 던져줬을 경우, throw를 통해 예외를 발생시켰을 경우에도 마찬가지입니다.

throws의 경우 호출하는 쪽에 해당 예외를 처리하는 코드가 없어도 되고, throw의 경우에도 발생하는 메서드에

해당 예외를 처리하는 코드가 없어도 됩니다. 해당 예외를 처리하는 것은 선택사항입니다.



이상 예외처리에 관한 포스팅을 마치겠습니다.

읽어주셔서 감사합니다.

'JAVA,JSP' 카테고리의 다른 글

리플렉션(2), Class 생성, Method 실행  (0) 2016.08.07
리플렉션(1), Class 클래스  (5) 2016.07.29
예외처리(1)  (0) 2016.06.30
java.lang.NoSuchMethodError  (1) 2016.06.28
동일성, 동등성  (4) 2016.06.24