
Closed icons created by Smashicons - Flaticon
아래와 같은 코드에서 try 블럭 내에서 생성되어 BufferedInputStream에게 전달되는 FileInputStream 인스턴스는 try-with-resources 문에 의해 자동으로 close 되는건지 의문이 생겼다. 이 블로그 글을 쓰신 분에게 도움을 많이 받았다. 결론은 try 블럭 내에서 명시적인 변수로 선언되지 않은 인스턴스는 자동으로 close 되지 않는다.
try (InputStream inputStream = new BufferedInputStream(new FileInputStream(srcFile))) {
    dstBuffer.writeBytes(inputStream, (int) srcFile.length());
} ... 그러나 BufferedInputStream 구현을 살펴보면 close할 때 내부 참조 스트림을 함께 닫아주는 것을 볼 수 있다. 위와 같은 상황에서 결론적으로 try-with-resources 문에 의해 닫기가 보장되는 것이 아니라 BufferedInputStream 구현에 의해 닫기가 보장되는 것임을 알 수 있다. try-with-resources 문을 사용할 때 주의가 필요하겠다.
public void close() throws IOException {
    byte[] buffer;
    while ( (buffer = buf) != null) {
        if (U.compareAndSetReference(this, BUF_OFFSET, buffer, null)) {
            InputStream input = in;
            in = null;
            if (input != null)
                input.close(); // 내부 참조 스트림을 닫습니다.
            return;
        }
        // Else retry in case a new buf was CASed in fill()
    }
}최종적으로 이해한 것을 테스트 코드로 작성해 보면 다음과 같다.
public class TryWithResourcesTest {
    @Test
    void notDeclaredAsVariable() throws Exception {
        try (Outer outer = new Outer(new Inner())) {
            // do something
        }
        // Result :
        // Outer.close()
    }
    @Test
    void declaredAsVariable() throws Exception {
        try (Inner inner = new Inner();
             Outer outer = new Outer(inner)) {
            // do something
        }
        // Result : 
        // Outer.close()
        // Inner.close()
    }
    static class Outer implements AutoCloseable {
        Inner inner;
        Outer(Inner inner) {
            this.inner = inner;
        }
        @Override
        public void close() throws Exception {
            System.out.println("Outer.close()");
        }
    }
    static class Inner implements AutoCloseable {
        @Override
        public void close() throws Exception {
            System.out.println("Inner.close()");
        }
    }
}