try with resources 문법은 try-catch문에서 선언된 객체들에 대해 try문을 벗어날 때 자동으로 자원을 해제해주는 문법이다. 

 

사실 여기서 글 작성을 완료해도 되지만..예시를 들어야겠죵?


기존에는 다음과 같이 자원을 해제했었다.

 

try {
    is = new FileInputStream("file.txt");
    dis = new DataInputStream(is);
    // ...생략
} catch (IOException e) {
    e.printStackTrace();
} finally {
    dis.close();
}

 

DataInputStream을 이용해 파일로부터 데이터를 읽는 코드로, 데이터를 읽다가 예외가 생겨도 finally블록의 close를 통해 자원을 해제한다. 그러나 사실 close()가 예외를 발생시킬 수 있다는 함정이 숨어 있다. 따라서 finally블록 안에서 다시 한 번 try catch를 해줘야 한다.

 

try {
    is = new FileInputStream("file.txt");
    dis = new DataInputStream(is);
    // ...생략
} catch (IOException e) {
    e.printStackTrace();
} finally {
    try {
        if (dis != null) {
            dis.close();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

 

그러나 indent가 꽤나 늘어나게 되는 걸 볼 수 있다. 한 눈에 봐도 코드가 더러워진다..좀 더 쉽게 자원을 해제하고 싶은 우리를 위한 바로 그 문법! try-with-resources문법이다. try의 괄호 () 안에 객체를 생성하는 코드를 넣으면, 그 객체는 따로 close()를 호출하지 않아도 try블록을 벗어나는 순간 자동적으로 close()를 호출하게 된다.

 

try (is = new FileInputStream("file.txt");
    dis = new DataInputStream(is)) {
    // ...생략
} catch (IOException e) {
    e.printStackTrace();
}

 

그렇다고 아무 객체나 냅다 반납(해제)가 가능한 건 아니다. try-with-resources문법으로 해제되고 싶은(?) 객체는 AutoCloseable이라는 인터페이스를 구현을 해야한다. 다음 코드가 AutoCloseable인터페이스다.

 

public interface AutoCloseable {
    void close() throws Exception;
}

 


코드의 복잡도를 줄여준다는 점 외에도 자원 해제를 해야 하는 경우 try-with-resources문법을 사용하는 게 좋은 이유는 또 하나 있다. 그건 바로 에러 스택 트레이스가 누락될 수 있다는 점이다. 다음과 같은 클래스가 있다고 해보자.

 

public class CloseableResource implements AutoCloseable {
    public void exceptionWork() throws WorkException {
        System.out.println("exceptionWork()가 호출됨!");
        throw new WorkException("WorkException 발생!!");
    }

    public void close() throws CloseException {
        System.out.println("close()가 호출됨!");
        throw new CloseException("CloseException 발생!!");
    }
}

class WorkException extends Exception {
    WorkException(String message) {
        super(message);
    }
}

class CloseException extends Exception {
    CloseException(String message) {
        super(message);
    }
}

 

그리고 다음과 같은 try-catch-finally문이 있다고 하자.

 

CloseableResource cr = null;
try {
    cr = new CloseableResource();
    cr.exceptionWork();
} finally {
    if (cr != null) {
        cr.close();
    }
}

 

우선 try블록에서 WorkException를 발생시킨다. 그리고 예외의 발생여부에 상관없이 항상 실행되는 finally 블록에서 close를 해주는데, 이 때 CloseException도 발생될 것이다. 그러면 우리의 상식(?)으로는 에러 스택 트레이스에 Work, CloseException이 둘 다 쌓여야 한다. 그러나 결과는..

 

 

보다시피 try블록에서 발생했던 WorkException이 누락된 모습이다. 비단 try블록 뿐만이 아닌 catch블록에서 발생된 예외도 이와 같은 상황에선 누락된다. 이러한 문제가 실무에서 발생됐다면.. 그 원인을 파악하기가 좀처럼 쉽지만은 않을 것이다.

 

그러나 다음과 같이 try-with-resources문으로 작성했다면 어떨까.

 

try (CloseableResource cr = new CloseableResource()) {
    cr.exceptionWork();
}

 

WorkException이 일어나고 try블록을 벗어나면서 close()가 호출되며 CloseException도 일어날 것이다. 결과는..

 

 

에러 트레이스가 누락되지 않은 모습을 볼 수 있다!! 때문에, 자원을 해제하는 경우 try-with-resources문법을 쓰는게 좋을 것이다.

 

 

 

+ Recent posts