Media Log


1. 예외 처리(Exception Handling)


우리가 이번에 배울 예외 처리(Exception Handling)에서의 '예외'는, 프로그램 실행 중 예외의 경우가 발생하여 비정상 종료되거나 잘못 작동하는 상황을 말합니다. 그렇다면 예외 처리는 무엇일까요? 예외 처리는 예외가 발생하는지 검사하고 만약 예외가 발생하면 프로그램이 갑자기 비정상 종료되는 것을 방지하고 처리하게 됩니다. 예를 들자면, 우리가 사칙연산이 가능한 계산기를 만들었다고 칩시다. 이 계산기 프로그램을 개발한 개발자는 프로그램의 모든 기능이 정상적으로 작동하는지 확인하기 위해 직접 테스트를 해보았습니다. 그런데, 나눗셈을 테스트 하는 중 어떠한 수를 0으로 나눠버리는 상황을 만났습니다. 사실상 숫자를 0으로 나눌수는 없기에 에러가 발생하여 프로그램이 종료됩니다. 


아래의 예제는 이해를 돕기위해 사용자에게 두개의 숫자를 입력받아 나눈 뒤의 결과를 출력하는 예제입니다.

import java.util.Scanner;


class calculators {

    public static void main(String args[]) {

        Scanner sc = new Scanner(System.in);

System.out.print("피제수를 입력하세요: ");

int num1 = sc.nextInt();

System.out.print("제수를 입력하세요: ");

int num2 = sc.nextInt();


System.out.println(num1 + "을 " + num2 + "로 나눈 값은 " + num1 / num2 + "입니다.");

    }

}


한번 피제수에 50을, 제수에 10을 입력하여 나눗셈을 진행해보도록 하겠습니다. 

피제수를 입력하세요: 50

제수를 입력하세요: 10

50을 10로 나눈 값은 5입니다.


결과를 보시면 정상적으로 결과는 출력되었고, 오류가 발생하여 프로그램이 종료되는 일이 없습니다. 그렇다면 이번엔 제수에 0을 넣게된다면 어떻게 될까요?


Exception in thread "main" java.lang.ArithmeticException: / by zero

        at calculators.main(Clock.java:12)


피제수를 0으로 나누는 것은 불가능하므로 예외가 발생하여 프로그램이 종료되었습니다. 여기에서 자바는, 예외가 발생하더라도 개발자가 처리할 수 있도록 예외의 종류를 정의하고, 여러가지 구문들을 제공합니다. 이번 강좌에서는  여러 구문들 중 하나인 try~catch와 finally, throws, throw 등에 대해서 알아보려고 합니다. 먼저 try~catch에 대해 알아보도록 하겠습니다.


2. try~catch


try~catch 구문은 예외가 발생하는 부분(try)과, 예외가 처리되는 부분(catch)으로 나뉩니다. 이 try~catch문을 사용하면, 예외가 발생하더라도 프로그램이 비정상 종료되지 않고 정상적으로 실행할 수 있게 합니다. 아래는 try~catch문의 사용 방법입니다.


try {

예외가 발생할 위험이 있는 코드

} catch (예외타입 예외명) {

예외를 처리하는 코드

}


그리고 아래는 런타임 예외(Runtime Exception)의 종류 입니다.


예외 타입

설명 

ArithmeticException

어떤 수를 0으로 나누는 것과 같이 비정상 계산 중 발생

NullPointerException

NULL 객체 참조시 발생 

IllegalArgumentException

메소드의 전달 인자값이 잘못될 경우 발생 

IllegalStateException

객체의 상태가 메소드 호출에는 부적합할 경우 발생 

 IndexOutOfBoundsException

index 값이 범위를 넘어갈 경우 발생 

 UnsupportedOperationException

객체가 메소드를 지원하지 않은 경우 발생 

 SecurityException

보안 위반 발생 시 보안 관리 프로그램에서 발생 

 ProviderException

구성 공급자 오류시 발생 

 NoSuchElementException

구성요소가 그 이상 없는 경우 발생 

 ArrayStoreException

객체 배열에 잘못된 객체 유형 저장시 발생 

 ClassCastException

클래스 간의 형 변환 오류시 발생 

 EmptyStackException

스택이 비어있는데 요소를 제거하려고 할시 발생


위의 타입 말고도, IllegalMonitorStateException(모니터 상태 오류), MissingResourceException(자원 누락 오류) 등등이 있으며 그 외의 Exception에는 IOException(파일 입출력 예외), ClassNotFoundException(지정된 클래스가 없을 경우 발생) 등 필요하시다면 다른 예외 타입도 적어두겠습니다.


예외 타입도, 각각의 예외 타입이 의미하는 것도, try~catch 구문의 사용법도 알게 되었으니 이제 한번 try~catch 구문을 사용해봅시다. 아래의 예제는 아까의 예제에 try~catch 구문을 적용한 예제입니다.


import java.util.Scanner;


class calculators {

    public static void main(String args[]) {

        Scanner sc = new Scanner(System.in);

try {

System.out.print("피제수를 입력하세요: ");

int num1 = sc.nextInt();

System.out.print("제수를 입력하세요: ");

int num2 = sc.nextInt();

System.out.println(num1 + "을 " + num2 + "로 나눈 값은 " + num1 / num2 + "입니다.");

} catch (ArithmeticException ae) {

System.out.println("피제수를 0으로 나눌 수는 없습니다. (" + ae + ")");

}

    }

}


결과:

피제수를 입력하세요: 50

제수를 입력하세요: 0

피제수를 0으로 나눌 수는 없습니다. (java.lang.ArithmeticException: / by zero)


코드를 보시면, 7행에서 try가 등장했습니다. try 이후에 등장하는 괄호 내의 코드에서 예외가 발생하게 된다면 이 예외를 잡아서(catch) 예외 처리를 하게 됩니다. 13행에서는 예외 타입이 ArithmeticException으로, 만약에 피제수를 0으로 나누려고 한다면 예외가 발생하게 되어 예외 처리부분으로 이동하고 "피제수를 0으로 나눌 수는 없습니다."라는 문자열이 출력되고 프로그램이 종료될 것입니다. 그런데 만약에, ArithmeticException이 아닌 다른 타입의 예외가 발생하면 어떻게 될까요? 답은 '잡지 못한다' 입니다. 이럴 경우에는 catch문을 하나 더 달아서 처리할 수 있습니다. 즉, 하나의 try에 여러개의 catch가 추가 될 수 있습니다. 정리하자면 이렇습니다. 우리가 피제수를 0으로 나누려고 한다면 예외가 발생하고 이 상황을 처리하기 위하여 ArithmeticException 클래스가 객체로 생성됩니다. 그런 뒤에 이 참조값을 catch 영역에 전달해주는 것입니다. 


이제 이 try~catch 구문에 finally 구문을 삽입해보도록 하겠습니다.


3. finally


예제를 통해 finally 구문은 어떠한 기능을 하는지 바로 알아보도록 하겠습니다.


import java.util.Scanner;


class calculators {

    public static void main(String args[]) {

        Scanner sc = new Scanner(System.in);

try {

System.out.print("피제수를 입력하세요: ");

int num1 = sc.nextInt();

System.out.print("제수를 입력하세요: ");

int num2 = sc.nextInt();

System.out.println(num1 + "을 " + num2 + "로 나눈 값은 " + num1 / num2 + "입니다.");

} catch (ArithmeticException ae) {

System.out.println("피제수를 0으로 나눌 수는 없습니다. (" + ae + ")");

} finally {

System.out.println("finally 영역이 실행되었습니다.");

}

    }

}


예외 발생시:

피제수를 입력하세요: 50

제수를 입력하세요: 0

피제수를 0으로 나눌 수는 없습니다. (java.lang.ArithmeticException: / by zero)

finally 영역이 실행되었습니다.


예외 미발생시:

피제수를 입력하세요: 50

제수를 입력하세요: 10

50을 10로 나눈 값은 5입니다.

finally 영역이 실행되었습니다.


코드와 결과만 보아서는, finally 영역은 예외가 발생하거나 발생하지 않아도 실행됩니다. 이 finally 영역은 예외상황을 무시하고 반드시 실행해야만 하는 코드가 있을 경우에 필요한 영역입니다. 


넘어가서, 다음은 throw, throws에 대해 알아보도록 하겠습니다.


4. throw, throws


여기서 throw의 사전적 의미 그대로 throw는 '던지다'라는 의미를 지니고 있습니다. 그렇다면 자바에서는 어떻게 쓰일까요? 말 그대로 '예외를 던지다, 발생시키다'라는 의미를 가지고 있습니다. throw 키워드는 예외 클래스를 만들 수 있게 하고, 강제로 예외를 발생시킬 수 있게 하는 특징이 있습니다. 그리고 throws 키워드는 메소드 호출 시 예외를 발생시키고 싶을 경우에 사용됩니다.


우선 throw 키워드에 대해 알아보도록 하겠습니다. 다음은 throw 키워드를 사용하여 강제로 예외를 발생시키는 예제입니다.


class throwexample {

    public static void main(String args[]) {

        throw new NullPointerException();

    }

}


에러:

Exception in thread "main" java.lang.NullPointerException

        at throwexample.main(Clock.java:3)


강제로 예외를 발생시키는 throw 키워드에 의해 NullPointerException 예외가 일어나고 프로그램이 종료됬습니다.

이 throw 키워드는, 다음과 같은 형태로 많이 쓰이며 프로그래머의 판단에 따라 처리할 수 있게 해줍니다.


throw new Exception();

ExceptionClass ext = new ExceptionClass();

throw ext;


또한 우리가 Exception 클래스를 상속하여 직접 예외를 만들 수 있습니다. 이해를 돕기 위해 값이 0 아래로 입력되면 예외가 발생될 수 있게 예외 클래스를 새롭게 만들어보도록 하겠습니다.


import java.util.Scanner;


class NegativeException extends Exception {

public NegativeException() {

super("음수는 입력될 수 없습니다.");

}

}


class throwexample {

public static void main(String args[]) {

Scanner sc = new Scanner(System.in);

System.out.print("숫자를 입력하세요: ");


try {

int num = sc.nextInt();

System.out.println(inputnum(num));

} catch (NegativeException ne) {

System.out.println(ne);

}

}


public static int inputnum(int num) throws NegativeException {

if (num < 0) {

NegativeException ext = new NegativeException();

throw ext;

}

return num;

}

}


양수 입력 시:

숫자를 입력하세요: 4

4


음수 입력 시:

숫자를 입력하세요: -4

NegativeException: 음수는 입력될 수 없습니다.


코드를 보시면, 3행에서 Exception 클래스를 상속하는 NegativeException 클래스가 정의되었습니다. 즉, NegativeException은 예외 클래스죠. 5행에서는 상위 클래스 Exception 클래스의 생성자 호출을 하며 옆의 문자열을 매개변수로 넘겨주고 있죠. 15~16행은 숫자를 입력받고 inputnum 메소드를 호출합니다. 여기서 주의하셔야 할것은 throw가 아닌 throws가 쓰였다는 것이죠. 이는, 이 메소드에서 어떠한 Exception을 던질 수 있는지 표시할때 사용됩니다. 즉, NegativeException 예외가 발생하면 이 메소드가 호출된 곳으로 던져버리겠다는 말입니다. 만약 예외가 발생하지 않았을 경우에는 그냥 num의 값을 반환하고 끝나죠. 


만약 -4를 입력했다고 합시다. 그렇다면 -4란 값이 inputnum 메소드의 매개변수 num으로 넘어갑니다. 그런 뒤에 num과 0을 비교합니다. 0이 num보다 크다면, 즉 음수라면 throw 키워드에 의해 예외가 발생되는거죠. -4는 0보다 작기에 throw에 의해 예외가 발생하고 throws에 의해 메소드가 호출된 곳으로 던져지게 됩니다. 그리고 catch가 그것을 잡아서 무엇이 에러인지 출력하게 되는거죠. (throw 키워드는 Exception을 던질 때 사용되며, throws는 던질 수 있는 Exception을 표시합니다.)


여기서 강좌 마치겠습니다. 수고하셨습니다.


다음 강좌는 쓰레드(Thread)에 관한 강좌를 할 예정입니다. 

저작자 표시
신고
  1. 김승현 at 2012.10.09 18:14 신고 [edit/del]

    감사합니다~

    Reply
  2. 팬돌이 at 2012.12.15 01:39 신고 [edit/del]

    덕분에 책 없이도 잘 이해하고 갑니다 감사합니다 ㅎㅎ

    Reply
  3. Javaman at 2014.09.03 16:30 신고 [edit/del]

    좋은 자료 정말 고맙습니다!

    Reply
  4. 지나가던행인 at 2015.11.25 20:16 신고 [edit/del]

    저는 메인메소드를 public static void main(String[] args) throws NegativeException 라고 선언해야 실행되는데 이유가 무엇 인가요?

    Reply
    • BlogIcon EXYNOA at 2015.11.25 21:14 신고 [edit/del]

      급하게 온라인 IDE를 통해 예제의 결과를 확인하였으나 아무런 이상이 없었습니다.
      개발환경을 명시해주시고, 어떠한 오류가 발생하시는지 같이 적어주세요.

  5. 지나가던공부쟁이 at 2016.07.27 12:08 신고 [edit/del]

    공부중에 질문 드립니다. try-catch 문은 자주 사용하는 것을 봤는데, throw, throws의 사용 빈도와 중요도는 어떻게 되나요?

    Reply
  6. 나그네 at 2016.10.20 18:26 신고 [edit/del]

    글만으로도 진짜 잘 이해할 수 있어요~좋은 글 감사합니다!

    Reply

submit

티스토리 툴바