본문 바로가기

java

[JAVA] Try-with-Resouce가 코드를 만들어 주는 방법

자바 7부터 try-with-resource 가 등장했다. try-with-resource를 사용하면 코드의 가독성이 훨씬 좋아진다는 장점이 있다. 

아래의 예제를 통해 살펴보자.

[기존 try-catch-finally] 

 static void copy(String src, String dst) throws  IOException {
        InputStream in = new FileInputStream(src);
        try{
            OutputStream out = new FileOutputStream(dst) ;
            try{
                byte[] buf = new byte[BUFFER_SIZE];
                int n;
                while ((n = in.read(buf)) >= 0)
                    out.write(buf , 0 , n);
            } finally {
                out.close();
            }
        }finally {
            in.close();
        }
    }

[try-with-resource]

  static void copy(String src, String dst) throws IOException {
        try (InputStream in = new FileInputStream(src);
                OutputStream out = new FileOutputStream(dst);) {
            byte[] buf = new byte[BUFFER_SIZE];
            int n;
            while ((n = in.read(buf)) >= 0)
                out.write(buf, 0, n);

        }
    }

 

 

한눈에 보기에도 기존의 try-catch-finally 는 중첩된 코드로 가독성이 좋지 않았다. 

하지만 단순히 가독성만을 위해 try-resource 코드가 생긴것은 아닐 것이다. 

기존 코드가 추가로 좋지 않았던 점은 기존 try-catch-finally 코드는 Exception을 모두 보여주지 않는 것이었다. 

 

아래 예제를 통해 살펴보자.  BefferedReader 를 구현한 BadBufferedReader 클래스이다.

상속을 통해 구현된 readLine() 과 close() 에서 각각의 Exception 을 발생하고 이 클래스를 

public class BadBufferedReader extends BufferedReader {
    public BadBufferedReader(Reader in, int sz) {
        super(in, sz);
    }

    public BadBufferedReader(Reader in) {
        super(in);
    }

    @Override
    public String readLine() throws IOException {
        throw new CharConversionException();
    }

    @Override
    public void close() throws IOException {
        throw new StreamCorruptedException();
    }
}

 

JDK7 에 등장한 try-with-resource 구문과 이전의 try-catch-finally 구문안에서 각각 실행하여 Exception 을 모두 발생시켜 볼 예정이다. 

[try-with-resource]

static String tryResourceExample(String path) throws IOException {
    try(BufferedReader br = new BadBufferedReader(new FileReader(path))) {
        return br.readLine();
    }
}

[try-catch-finally]

static String tryFinallyExample(String path) throws IOException {
    BadBufferedReader br = new BadBufferedReader(new FileReader(path));
    try{
        return br.readLine();
    }catch (Exception e) {
        System.out.println(e.getCause());
    }finally {
        br.close();
    }
    return null;
}

 

[try-with-resource console]

[try-catch-finally console]

 

기존 try-catch-finally 에서는 처음 발생한 Exception이 보이지 않고 가장 밖에 있던 Exception만 로그에 찍히지만 try-with-resource 에서는 그대로 stack 에 쌓여 로그에 남겨진다.

어떻게 stack 에 두개의 두 exception 로그를 남길 수 있는지 try-with-resource (바이트 코드에서 디컴파일된 클래스 파일)로 확인할 수 있다. 

 

try-with-resource로 구현된 코드를 바이트 코드에서는 위와 같이 구현해 준다. 

finally 가 사라지고 중첩된 try-catch 문으로 

throw 문 발생시 addSuppressed() 함수로 무시될 수 있는 예외를 포함 시키고 있다.  그래서 stack 에 같이 남을 수 있는 것이다.

addSuppressed() 함수는 무시되는 예외를 표시하기 위해 Java7 에서 포함된 함수이다. 

 

이밖에 try-with-resource의 가독성에서의 장점이라 하면 try() 안에 여러개의 리소스를 넣어서 한번에 사용할 수 있다는 점이다.

try() 함수의 Required Type 이 AutoCloseable 인것도 추가로 알아두면 좋다. 

try-with-resource 에서 AocoCloseable에 있는 close()를 직접 호출하여 finally안에서 close() 를 명시적으로 호출 할 필요가 없다. 

public interface Closeable extends AutoCloseable {

    /**
     * Closes this stream and releases any system resources associated
     * with it. If the stream is already closed then invoking this
     * method has no effect.
     *
     * <p> As noted in {@link AutoCloseable#close()}, cases where the
     * close may fail require careful attention. It is strongly advised
     * to relinquish the underlying resources and to internally
     * <em>mark</em> the {@code Closeable} as closed, prior to throwing
     * the {@code IOException}.
     *
     * @throws IOException if an I/O error occurs
     */
    public void close() throws IOException;
}
static void example(String src, String dst) throws IOException {
    try (InputStream in = new FileInputStream(src);
         OutputStream out = new FileOutputStream(dst);) {
        byte[] buf = new byte[BUFFER_SIZE];
        int n;
        while ((n = in.read(buf)) >= 0)
            out.write(buf, 0, n);

    }
}

 

반응형