API를 사용할 때 설계자의 의도에 따라서 예외를 반드시 처리해야 하는 경우가 있다
package com.yuri.javatutorials.exception;
import java.io.*;
public class CheckedExceptionDemo {
public static void main(String[] args) {
BufferedReader bReader = null;
String input = null;
try {
bReader = new BufferedReader(new FileReader("output.txt"));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
try {
input = bReader.readLine();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(input);
}
}
package com.yuri.javatutorials.exception;
class B {
void run() {
}
}
class C {
void run() {
B b = new B();
b.run();
}
}
public class ThrowExceptionDemo {
public static void main(String[] args) {
C c = new C();
c.run();
}
}
ThrowExceptionDemo클래스의 메소드 main이 C클래스를 인스턴스화 시켰고 , c 인스턴스의 run 이라는 메소드를 호출시켰다. 메소드 run 안에서는 클래스 B를 인스턴스화 했고, 그것을 run 했다.
클래스 B의 run 메소드를 사용하고 있는 곳은 클래스 C의 run이 B.의 run을 사용하고 있다. B에 대해서 C는 사용자의 관계에 있다고 할 수 있다. 그리고 Thorw익셉션은 C에 대해서 사용자이다. B의 run에서 예외가 발생했을 때 B가 처리하지 않고 그것을 C, 다음 사용자에게 던질 수 있다. C역시 다음 사용자에게 넘길 수도 있다. Throw역시 넘길 수 있는데 일반 사용자에게 넘긴다는 뜻은 예외를 처리하지 않고 종료하겠다는 의미이다.
ThrowExceptionDemo.main(클래스 ThrowExceptionDem의 메소드 main)은 C.run의 사용자이다. C.run은 B.run의 사용자이다. 반대로 B.run의 다음 사용자는 C.run이고 C.run의 다음 사용자는 ThrowExceptionDem.main이 되는 셈이다. 파일을 읽은 로직을 추가해보자.
B -> C -> Throw -> 일반 사용자
package com.yuri.javatutorials.exception;
import java.io.*;
class B {
void run() {
BufferedReader bReader = null;
String input = null;
try {
bReader = new BufferedReader(new FileReader("output.txt"));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
try {
input = bReader.readLine();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(input);
}
}
class C {
void run() {
B b = new B();
b.run();
}
}
public class ThrowExceptionDemo {
public static void main(String[] args) {
C c = new C();
c.run();
}
}
B.run이 FileReader의 생성자와 BufferedReader.readLine가 던진 예외를 try...catch로 처리한다. 즉 B.run이 예외에 대한 책임을 지고 있다.
그런데 B.run이 예외 처리를 직접 하지 않고 다음 사용자 C.run에게 넘길 수 있다.
package com.yuri.javatutorials.exception;
import java.io.*;
class B {
void run() throws IOException, FileNotFoundException {
BufferedReader bReader = null;
String input = null;
bReader = new BufferedReader(new FileReader("output.txt"));
input = bReader.readLine();
System.out.println(input);
}
}
class C {
void run() throws FileNotFoundException, IOException{
B b = new B();
b.run();
}
}
public class ThrowExceptionDemo {
public static void main(String[] args) {
C c = new C();
try {
c.run();
} catch (FileNotFoundException e) {
System.out.println("output.txt 파일이 필요함");
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 만약 output.txt 을 삭제 후 실행해 보면 output.txt 파일이 필요함이 출력됨
catch는 자기가 처리하는 것
throw는 다음 사용자에게 책임을 넘기는 것!
예외 처리는 귀찮은 일이다. 그래서 예외를 다음 사용자에게 전가(throw)하거나 try...catch로 감싸고 아무것도 하지 않고 싶은 유혹에 빠지기 쉽다. 하지만 예외는 API를 사용하면서 발생할 수 있는 잠재적 위협에 대한 API 개발자의 강력한 암시다. 이 암시를 무시해서는 안 된다. 물론 더욱 고민스러운 것은 예외 처리 방법에 정답이 없다는 것이겠지만 말이다.
이 글은 생활코딩의 자바 강좌를 바탕으로 정리한 내용입니다.