자바(Java) 강의

17. 예외처리 (Exception, throw and throws) (3)

삐멜 2019. 5. 20. 11:12

이 포스트에서는 임의의 상황에서 새 Exception 오브젝트를 만드는 방법(throw)과 어떤 메서드가 어떤 예외를 발생시킬 수 있는지 명시하는 방법(throws)에 대해 알아보도록 한다.

이전 포스트

목표

  • throw
  • throws

throw

이전 두 포스트에서 JVM은 예외 상황이 생기면 새 예외 오브젝트를 만들어 던진다고 했다. 그렇다면 이 오브젝트는 JVM만 던질 수 있는것일까? 아니다. 만약 우리 개발자들이 어떤 상황은 허용되지 않는 예외상황이라고 정의하면 그 상황이 왔을 때 예외 오브젝트를 만들어 던질 수 있다. 예를들어보자.
import java.io.IOException;

public class IOService {
public String read() {
String text = ""; // read string from file;
if(text == null || text.isEmpty()) {
throw new IOException("Content is empty");
}
return text;
}
}
Main 클래스는 다음과 같다.
public class Main {
public static void main(String[] args) {
IOService ioService = new IOService();
ioService.read();
}
}
예를들어 IOService라는 클래스에 read라는 메서드가 있다고 치자. 이 메서드는 파일에서 텍스트를 읽어 text에 저장한다. 지금은 우리가 파일에서 텍스트를 읽는 법을 모르므로 읽은 텍스트가 빈 텍스트(“”)라고 가정하자. 우리는 빈 텍스트인경우 파일을 읽지 못한것과 동일한 취급을 하고싶다. 따라서 텍스트가 null이거나 empty인 경우 IOException을 던지고 싶다. 그럴 때, “throw (예외 오브젝트)” 키워드를 사용해 새 예외 오브젝트를 던질 수 있다. 이렇게 하고나면 컴파일 에러가 날 것이다. 

Error:(7, 13) java: unreported exception java.io.IOException;

must be caught or declared to be thrown

자바의 예외 중 어떤 예외는 개발자가 반드시 예외를 처리하도록 강요한다. 그 중 하나가 바로 IOException이다. 

연습하기

IOException대신 NullPointerException을 만들어 던져보자. java: unreported exception에러가 나는가? 

이를 해결하는 데에는 두가지 방법이 있다. 첫번째는 try-catch로 감싸 이 메서드 내에서 예외처리를 하는 것이다.
import java.io.IOException;

public class IOService {
public String read() {
String text = ""; // read string from file;
if (text == null || text.isEmpty()) {
try {
throw new IOException("Content is empty");
} catch (IOException e) {

}
}
return text;
}
}
하지만 이 방법은 위의 예에서는 의미가 없다. 우리는 이 메서드를 사용하는 개발자에게 이 예외를 처리하게 하고싶다. 왜? 개발자마다 이 예외를 처리하는 방법이 다를 수 있기 때문이다. 그리고 내가 예외를 throw하는데 내가 바로 처리할거라면 애초에 왜 throw하는가 그냥 리턴하면 될것을? 따라서 이 상황에서 try-catch를 사용하는것은 큰 의미가 없다. 다른 방법이 있을까? 다른 방법은 이 메서드를 부른 메서드로 예외를 다시 throw하는 것이다. 

throws

이 메서드를 부른 메서드로 예외를 다시 throw하기위해 메서드 끝에 throws XXXException하고 써준다. 이 예제에서는 throws IOException이라고 써주면 된다.
import java.io.IOException;

public class IOService {
public String read() throws IOException{
String text = ""; // read string from file;
if(text == null || text.isEmpty()) {
throw new IOException("Content is empty");
}
return text;
}
}
throws의 뜻은 무엇인가? 바로 이 메서드에서 일어나는 예외들(throws다음에 오는 예외들)은 이 메서드를 부른 메서드가 처리 해 준다고 가정한다는 뜻이다. 또는 이 메서드를 부른 메서드(Caller)에게 예외를 처리하는 의무를 주는 것이다. 따라서 Caller 메서드는 1)try-catch로 예외처리를 하거나 2)다시 Caller의 Caller메서드로 전파하는 방법 중 하나를 택해 예외 처리를 해야한다.
public class Main {
public static void main(String[] args) {
IOService ioService = new IOService();
ioService.read();
}
}
이렇게 하면 이번엔 read에서 컴파일 에러가 날 것이다.

Error:(4, 22) java: unreported exception java.io.IOException; must be caught or declared to be thrown

read메서드를 부르는 caller 메서드인 main이 IOException을 처리해야 하는 것이다. 방법은 두가지가 있다고 했다.
첫번째는 try-catch를 써서 이 메서드에서 해결하는 방법.

import java.io.IOException;

public class Main {
public static void main(String[] args) {
IOService ioService = new IOService();
try {
ioService.read();
} catch (IOException e) {

}
}
}

두번째는 throws를 이용해 Caller로 전파하는 방법. 이 경우 main이 가장 처음 불려지는 메서드라 결국 JVM으로 예외가 전파되고 예외는 처리되지 않은채로 종료되고 말것이다.

import java.io.IOException;

public class Main {
public static void main(String[] args) throws IOException {
IOService ioService = new IOService();
ioService.read();
}
}

이번 포스트에서는 새 예외를 만들어 throw하는 방법과 예외를 미루는처리하는 방법에 대해 알아봤다. 이제 파일 입출력에 대해 할 때가 된 것 같다. 다음 포스트부터는 파일 입출력에 대해 이야기하도록 하겠다.

다음 포스트: 18. 파일 입출력 (1) - 파일 생성