article thumbnail image
Published 2020. 4. 28. 17:40

지금까지 예외를 처리하는 방법으로 try...catch...finally를 배웠다.

이외에 다른 방법도 있다. 

throw를 사용하는 것이다.

throw는 예외처리를 다음 사용자에게 넘기는 것이다.

다음 사용자는 누구일까? 코드를 보자.

 

package org.opentutorials.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 클래스 ThrowExceptionDemo의 메소드 main()은 C.run의 사용자이다.

C.run은 B.run의 사용자이다.

반대로 B.run의 다음 사용자는 C.run이고 C.run의 다음 사용자는 ThrowExceptionDemo.main이 되는 셈이다.

 

B에서 예외가 발생할 수 있지만 여기서 처리하지 않고, 이 예외를 catch 하는 것을 C로 넘길 수 있다.

C에서 예외가 발생할 수 있지만 여기서 처리하지 않고, 이 예외를 catch 하는 것을 ThrowExceptionDemo로 넘길 수 있다.

ThrowExceptionDemo에서 예외가 발생할 수 있지만 여기서 처리하지 않고, 이 예외를 catch 하는 것을 일반 사용자로 넘길 수 있다.

파일을 읽은 로직을 추가해보자.


package org.opentutorials.javatutorials.exception;
import java.io.*;
class B{
    void run(){
        BufferedReader bReader = null;
        String input = null;
        try {
            bReader = new BufferedReader(new FileReader("out.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();
    }   
}

 

차이점

 

먼저 BufferedReader는 기본으로 제공되는 클래스가 아니기 때문에, 기본 자바 패키지가 아니기 때문에

import java.io.BufferedReader; 를 추가해야한다.

또한 FileReader 도 마찬가지이다.

import java.io.FileReader; 를 추가해야한다.

 

import java.io.FileNotFoundException;

import java.io.IOException;

 

그냥 이것을 다 포함하는 import java.io.*; 을 추가하면 된다.

 

 

위의 코드는 B.runFileReader의 생성자와 BufferedReader.readLine가 던진 예외를 try...catch로 처리한다.

즉 B.run이 예외에 대한 책임을 지고 있다.


그런데 B.run이 예외 처리를 직접 하지 않고 다음 사용자 C.run에게 넘길 수 있다. 아래의 코드를 보자.

package org.opentutorials.javatutorials.exception;
import java.io.*;
class B{
    void run() throws IOException, FileNotFoundException{
        BufferedReader bReader = null;
        String input = null;
        bReader = new BufferedReader(new FileReader("out.txt"));
        input = bReader.readLine();
        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 내부의 try...catch 구문은 제거되었고 run 옆에 throws IOException, FileNotFoundException이 추가되었다.

이것은 B.run 내부에서 IOException, FileNotFoundException에 해당하는 예외가 발생하면 이에 대한 처리를 B.run의 사용자에게 위임하는 것이다.

 

현재 이 코드 안에서 new FileReader() 하는 과정에서 발생하는 예외에 대한 책임을 지지 않기 때문에 try문을 없에도 로직에 문제가 없다.

또한 이 코드 안에서 bReader.readline() 하는 과정에서 발생하는 예외에 대한 책임을 지지 않기 때문에 try문을 없에도 로직에 문제가 없다.

 

B.run에서 예외에 대한 책임을 C.run으로 넘겼다.

위의 코드에서 B.run의 사용자는 C.run이다.

따라서 C.run은 이에 대한 책임을 져야 한다.


package org.opentutorials.javatutorials.exception;
import java.io.*;
class B{
    void run() throws IOException, FileNotFoundException{
        BufferedReader bReader = null;
        String input = null;
        bReader = new BufferedReader(new FileReader("out.txt"));
        input = bReader.readLine();
        System.out.println(input);
    }
}
class C{
    void run(){
        B b = new B();
        try {
            b.run();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
public class ThrowExceptionDemo {
    public static void main(String[] args) {
         C c = new C();
         c.run();
    }   
}

 

차이점은 아래와 같다.


이 책임을 다시 main에게 넘겨보자.

package org.opentutorials.javatutorials.exception;
import java.io.*;
class B{
    void run() throws IOException, FileNotFoundException{
        BufferedReader bReader = null;
        String input = null;
        bReader = new BufferedReader(new FileReader("out.txt"));
        input = bReader.readLine();
        System.out.println(input);
    }
}
class C{
    void run() throws IOException, FileNotFoundException{
        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("out.txt 파일은 설정 파일 입니다. 이 파일이 프로잭트 루트 디렉토리에 존재해야 합니다.");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }   
}

 

차이점은 아래와 같다.

 


여기서 catch (FileNotFoundException e) {} 문은 지워도 된다.

왜냐하면 FileNotFoundException의 조상은 IOException이기 때문이다.

FileNotFoundException은 IOException에 포함된다.

package org.opentutorials.javatutorials.exception;
import java.io.*;
class B{
    void run() throws IOException, FileNotFoundException{
        BufferedReader bReader = null;
        String input = null;
        bReader = new BufferedReader(new FileReader("out.txt"));
        input = bReader.readLine();
        System.out.println(input);
    }
}
class C{
    void run() throws IOException, FileNotFoundException{
        B b = new B();
        b.run();
    }
}
public class ThrowExceptionDemo {
    public static void main(String[] args) {
        C c = new C();
        try {
            c.run();
        } catch (IOException e) {
            System.out.println("out.txt 파일이 필요합니다");
        }
    }   
}

 

에러 메시지를 띄우는 것보다 출력 메시지를 주는 것은 사용자에게 전혀 다른 느낌을 준다.

왜냐? 이것은 예외상황을 어플리케이션이 관리하는 느낌을 주기 때문이다. 


out.txt 파일을 찾을 수 없는 상황은 B.run 입장에서는 어떻게 할 수 있는 일이 아니다. 

엔드유저인 애플리케이션의 사용자가 out.txt 파일을 루트 디렉토리에 위치시켜야 하는 문제이기 때문에 애플리케이션의 진입점인 메소드 main으로 책임을 넘기고 있다.

 

예외 처리는 귀찮은 일이다. 그래서 예외를 다음 사용자에게 전가(throw)하거나 try...catch로 감싸고 아무것도 하지 않고 싶은 유혹에 빠지기 쉽다. 하지만 예외는 API를 사용하면서 발생할 수 있는 잠재적 위협에 대한 API 개발자의 강력한 암시다. 이 암시를 무시해서는 안 된다. 물론 더욱 고민스러운 것은 예외 처리 방법에 정답이 없다는 것이겠지만 말이다.

 

catch는 자기가 예외를 처리하는 것이고

throw는 예외를 다음 사용자에게 책임을 넘기는 것이다.

'📌 java > java' 카테고리의 다른 글

java - Object 클래스  (0) 2020.04.30
java - throw new  (0) 2020.04.29
java - 예외의 강제  (0) 2020.04.28
java - finally  (0) 2020.04.28
java - 좀 더 다양한 exception들  (0) 2020.04.28
복사했습니다!