자바/자바기초

[자바] 5화 예외발생/이양(throw/throws)

khao 2016. 4. 3. 19:51

읽기에 앞서, 5화는 '4화 try/catch/finally, throws'와 연결되는 내용이므로 못 보신 분들은 보시는 것을 추천드립니다.


이번에는 강제로 예외를 발생시키는 예외발생에 대해 알아보겠습니다.

단어만 들으면 상당히 이상할 수 있습니다. 예외발생.. 예외를 일부러 만든다? 사실 쓰는 저도 당황스럽습니다. 왜냐하면 throw를 줘가면서 소스를 짜본 적이 없어서요.. 예외를 발생시키는 이유는 상위클래스에게 예외가 발생하였음을 알리기 위해 씁니다. 즉, 예외발생과 예외이양을 하여야 상위클래스가 무슨 예외가 발생하였는지 알 수 있습니다.

예외이양을 하는 방법은 throws를 사용하는 것입니다. 네, 맞습니다. 3화에서 본 try/catch, throws의 그 throws입니다. 3화에서는 throws는 예외를 넘기기만 할 뿐 try/catch처럼 사용자가 예외 발생에 대한 컨트롤을 할 수 없다고 했습니다. 사실 throws가 저런 기능밖에 없었다면 모든 프로그래머들이 try/catch밖에 사용하지 않았겠죠.


throws는 메소드를 호출한 쪽에게 예외를 던질 수 있습니다. "


물론 예외가 발생해야 던지겠죠? throws가 예외를 잘 던질 수 있도록 예외를 발생시켜주는 것이 throw입니다.

예외발생과 이양에 관해서는 예제를 보면서 하는 것이 편할 것 같습니다.


먼저 광부가 보석을 캘 때를 예외로 만들어봅시다. (간단하게 Exception을 상속받아 만들겠습니다.)

class OreException extends Exception{
}

실행할 main함수와 채석장에서 돌을 캐는 행동을 hitStone()이라는 메소드로 만들겠습니다.

public class test { public static void main(String[] args) { try { System.out.println("작업을 시작합니다."); hitStone(); System.out.println("광물을 발견하지 못했어요."); } catch(OreException e) { System.out.println("광물 발견!"); } } public static void hitStone() throws OreException { final int STONE = 1; final int DIAMOND = 2; int err = 0; int array[] = new int[10];   for(int i = 0; i < 9; i++) array[i] = STONE;   array[9] = DIAMOND; try{ for(int i = 0; i < 10; i++) { err = array[i]; if(array[i] == 1) System.out.println("두두두두"); else throw new OreException(); } } catch (OreException e) { System.out.printf("%d를 발견하였습니다.\n", err); throw e; } finally { System.out.println("채굴작업이 끝났습니다."); } } }

이 소스코드가 그림과 동일한 소스코드입니다. 실행시키면 아래 순서대로 결과가 출력됩니다.


예측한 것과 순서가 다르게 나오신 분들도 있을 것 같습니다. 소스코드가 실행된 순서에 대해서도 알아봅시다.




이렇게 설명을 같이 놓고 보니 이 소스코드는 예외가 발생한다면 main() 안에 있는 "광물을 발견하지 못했다"는 문구는 절대 출력되지 않겠네요. throw를 이용하여 예외를 발생시켜서 보석을 찾았는가에 대한 정보를 얻어낼 수 있었습니다. 예제에서는 비록 보석을 찾았는지에 대해서만 예외처리를 시켰지만 '곡괭이가 부러졌는가?'에 대해서도 같이 예외처리를 넣을 수 있습니다.

class OreException extends Exception{}
class NoShovelException extends Exception{}
 
public class test {
  public static void main(String[] args) {
    try {
    System.out.println("작업을 시작합니다.");
    hitStone();
    System.out.println("광물을 발견하지 못했어요.");
    }
    catch(OreException e) {
      System.out.println("광물 발견!");
    }
    catch(NoShovelException e) {
    }
    catch(Exception e) {
    }
  }
  public static void hitStone() throws Exception {
    final int STONE = 1;
    final int DIAMOND = 2;
    int shovel = 3, err = 0;
    int array[] = new int[10];
    for(int i = 0; i < 9; i++)
      array[i] = STONE;
    array[9] = DIAMOND;
    try{ 
      for(int i = 0; i < 10; i++) {
        err = array[i];
        if(shovel == 0)
          throw new NoShovelException();
        if(array[i] == 1)
          System.out.println("두두두두");
        else
          throw new OreException();
        shobel--;
      }
    }
    catch (OreException e) {
      System.out.printf("%d를 발견하였습니다.\n", err);
      throw e;
    }
    catch (NoShovelException e) {
      System.out.println("삽이 없습니다.");
      throw e;
    }
    finally {
      System.out.println("채굴작업이 끝났습니다.");
    }
  }
}



(삽으로 돌을 캔다는 것 자체가 이상하지만) 삽으로 돌을 3번 캐면 삽의 내구도가 0이 되어 삽이 없다는 말과 함께 작업을 끝내게 됩니다. 만약 main() 안에 있는 catch (NoShovelException e)안에 뭔가 써져있다면 해당 문구도 실행됩니다.  

throw는 라이브러리에서 많이 쓴다는 사실과 이런 것이 있다 정도로만 알고 있었는데 예문을 만들어보니 나름 throw도 재미있네요.