# ITEM 9: try-with-resources

자바 라이브러리에는 `close` 메서드를 호출해 직접 닫아줘야하는 자원들이 많다.(`InputStream`, `OutputStream`, `java.sql.Connection` 등) 자원 닫기는 클라이언트가 놓치기 쉬워 예측할 수 없는 성능 문제로도 이어진다. 이러한 경우 상당수가 안전망으로 `finalizer`를 활용하고 있지만, `finalizer`는 믿을만 하지 못하다.([item 8](https://github.com/dh00023/TIL/blob/master/Java/effective_java/2021-01-25-avoid-finalizer-and-cleaner.md))

전통적으로 자원이 제대로 닫힘을 보장하는 수단으로 `try-finally` 가 사용되었다.

```java
    static String firstLineOfFile(String path) throws IOException{
        BufferedReader br = new BufferedReader(new FileReader(path));
        try{
            return br.readLine();
        }finally {
            br.close();
        }
    }
```

기기에 물리적인 문제가 생겨 `firstLineOfFile` 메서드 안의 `readLine` 메서드가 문제가 생긴다면 `readLine()` 메서드가 예외를 던지고, 같은 이유로 `close` 메서드도 실패할 것이다. 이러한 상황에서 두번째 예외가 첫번째 예외를 삼켜, 스택 추적 내역에 첫번째 예외에 대한 정보는 남지 않게 된다. 두 번째 예외 대신 첫 번째 예외를 남길 수는 있지만, 코드가 너무 지저분해져서 실제로 그렇게 하는 경우는 거의 없다.

이러한 문제들은 java 7의 `try-with-resources` 덕에 모두 해결되었다. `try-with-resources` 구조를 사용하려면 해당 자원이 `AutoCloseable` 인터페이스를 구현해야하는데, 수 많은 인터페이스가 이미 `AutoCloseable`을 구현하거나 확장해두었다.

```java
    static String firstLineOfFile(String path) throws IOException{
        // try - with - resources
        try(BufferedReader br = new BufferedReader(new FileReader(path)){
            return br.readLine();
        }
    }
```

`readLine()`과 `close()` 호출 양쪽에서 예외가 발생하면, `close`에서 발생한 예외는 숨겨지고, `readLine`에서 발생한 예외만 기록이 된다. 또한, 숨겨진 예외들도 스택추적 내역에 **suppressed**라는 꼬리표를 달고 출력되며, `Throwable`에 추가된 `getSuppressed` 메서드를 이용해 프로그램 코드에서도 가져올 수 있다.

```java
    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 - with -resources

```java
try (SomeResource resource = getResource()) {
    use(resource);
} catch(...) {
    ...
}
```

try에 자원 객체를 전달하면, **try 코드 블록이 끝나면 자동으로 자원을 종료해주는 기능**으로 따로 `finally` 블록이나 모든 `catch` 블록에 종료 처리를 해주지 않아도 된다.

하지만, 이 구조를 사용하려면 해당 자원이 `AutoCloseable` 인터페이스를 구현해야한다.

```java
public interface AutoCloseable {

    void close() throws Exception;
}
```

또한, try안에 복수의 자원 객체를 전달할 수도 있다.

```java
try(Something1 s1 = new Something1();
    Something2 s2 = new Something2()) {

} catch(...) {
    ...
}
```

```java
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-finally`말고 `try-with-resources`를 사용해라. **코드는 더 짧고 분명해지며, 만들어지는 예외정보도 훨씬 유용**하다. 정확하고 쉽게 자원을 회수할 수 있다.

## 참고

* <https://ryan-han.com/post/java/try_with_resources/>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://dahye-jeong.gitbook.io/til/java/effective_java/2021-01-25-try-with-resources.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
