728x90

이 강의는 자바의 프로젝트를 어떻게 만드는지, 또한 빌드를 어떻게 하는지에 대한 강의를 진행하지 않는다.

그러나 자바의 기본적인, 그리고 자바에 필수적인 기능들도 분명 존재하고 이 블로그엔 그 작업에 필요한 포스팅도 함께 제공하고 있다.

그 정보를 확인하고 싶다면 여기를 참조하라. 양이 조금 되고 현재진행형으로 늘어나고 있으므로 페이지내의 찾기(ctrl+f 나 cmd+f)로 찾아보도록하자.


저번에 예외를 배운데 앞서서 이번에는 저번에 마저 설명하지 못한 부분들을 설명할 것이다.

여러분이 직접 예외를 발생시켜보는 것이다.

아래와 같은 상황을 보자.


package com.jiharu.main;

public class Main {

public static void main(String[] args) {
Person p = new Person("kukaro");
p.eat("밥");
p.eat("독");
}
}

이 클래스는 Main클래스이다. Person클래스는 아래와 같다.


package com.jiharu.main;

public class Person {
String name;

public Person(String name) {
this.name = name;
}

void eat(String food) {

System.out.println(food + "를 먹고 있습니다. 우적우적.");
}
}

이 예제는 매우 간단한 예제다.

여기서 문제가 있다. 우리는 독을 먹으면 죽을 것이다.

예제로 어쨋던 독을 먹게되는 상황을 예외로 던져보자.


package com.jiharu.main;

public class Person {
String name;

public Person(String name) {
this.name = name;
}

void eat(String food) throws Exception {
if (food.equals("독")){
throw new Exception();
}
System.out.println(food + "를 먹고 있습니다. 우적우적.");
}
}

코드가 조금은 달라졌다. 여기서 throw라는 코드로 인하여 Exception을 던졌다.

그리고 특정 메소드안에 예외를 던지는 구문이 있다면 반드시 메소드에 throws키워드를 사용해서

예외를 발생할 수 있음을 알려야만 한다. 즉 eat이라는 메소드를 보면 누가봐도 안에 예외를 던질 수 있다는걸 알 수 있다.

이것은 문법적으로 강제가 된다.

이제 다시 Main클래스를 보면 에러가 발생할 것이다.


이 상황에서 마우스를 얹어서 보면 예외를 핸들링하지 않아서, 예외를 처리하지 않아서 에러가 뜬다.

따라서 이 부분을 예외로 감싸서 예외처리를 해줘야한다.


package com.jiharu.main;

public class Main {

public static void main(String[] args) {
Person p = new Person("kukaro");
try {
p.eat("밥");
p.eat("독");
} catch (Exception e) {
e.printStackTrace();
}
}
}

이렇게 예외를 처리해주는 것이다.

그러면 내가 예외를 만드는것도 가능할까?

물론 그것 역시 가능하다.

예외도 일종의 class이기 때문이다.


package com.jiharu.main;

public class EatPoisonException extends Exception{
@Override
public String getMessage() {
return "독을 잡수셨습니다.";
}
}

사실 Exception은 보통 만들어도 여러가지 구현할 필요는 없다.

사람에게 이게 무슨 예외인지만 알면되니 설명만 추가하는게 보통이다.

따라서 보통의 경우 getMessage만 오버라이딩 해서 쓰는 경우가 많다.

이제 다시 Person을 바꿔보자.


package com.jiharu.main;

public class Person {
String name;

public Person(String name) {
this.name = name;
}

void eat(String food) throws EatPoisonException {
if (food.equals("독")){
throw new EatPoisonException();
}
System.out.println(food + "를 먹고 있습니다. 우적우적.");
}
}

여러분은 EatPoisonException을 던지게 코드를 수정했다.

throw는 return과 같다. throw가 발생하면 이하의 코드는 실행되지 않고 예외를 던진다.

이제 Main을 실행해보면 아래와 같은 결과를 얻을 수 있다.


예외가 발생했고 우리가 정한 getMessage가 정상적으로 출력되는걸 확인할 수 있다.


그러면 이제 한가지 궁금증이 생길것이다. 뭐 안생길수도 있지만.

우리가 예외를 선언하자 예외는 문법적으로 강제가 되서 무조건 try catch문을 써서 예외를 잡아 냈다.

그러나 우리가 ArithmeticException같은것은 try catch문으로 감싸지 않아도 정상실행이 됬었다.

무슨 말인지 모르겠는가? 새로운 상황을 보자.


package com.jiharu.main;

public class DeepSleepException extends RuntimeException{
@Override
public String getMessage() {
return "하루종일 잠만 자고 있음.";
}
}

새로운 예외를 작성했다. 이 예외는 잘보면 RuntimeException을 상속받았다.

별거 없는 일반적인 예외와는 조금은 쓰는 방법이 다르다.

이제 다시 Person으로 돌아가보자.


package com.jiharu.main;

public class Person {
String name;

public Person(String name) {
this.name = name;
}

void eat(String food) throws EatPoisonException {
if (food.equals("독")) {
throw new EatPoisonException();
}
System.out.println(food + "를 먹고 있습니다. 우적우적.");
}

void sleep(int time) {
if (time >= 24) {
throw new DeepSleepException();
}
System.out.println(time + "시간 자고 일어납니다.");
}
}

보면 알겠지만 throws로 명시적으로 예외를 던진다는 선언이 없지만 그래도 문법오류가 안뜬다.

이까지만해도 더 이해가 안가는가? 이제 Main을 가보자.


package com.jiharu.main;

public class Main {

public static void main(String[] args) {
Person p = new Person("kukaro");
p.eat("콜라");
p.sleep(25);
}
}

이러한 코드를 봣을때 eat과 sleep은 서로 다른 종류의 예외를 던질 가능성이 존재한다.

그러나 둘의 취급은 다르다.


보면 eat만 문법적으로 강제되고 sleep은 문법적으로 강제되지 않는다.

따라서 eat은 무조건 try catch문 사용이 강제되지만 sleep은 써도 되고 안써도 된다.

물론 특정 상황에서 예외가 발생하는건 똑같다.


이렇게 문법적으로 강제시키고 싶지않다면 RuntimeException을 상속받아서 사용하면 된다.

이 계열은 Unchecked Exception으로 분류되어서 문법적으로 강제로 체크시키지 않는다.

문법적으로 강제시키고 싶다면 Exception을 상속받으면 된다.

이 계열은 Checked Exception으로 분류되어서 문법적으로 반드시 예외처리를 해주어야한다.



+ Recent posts