yeonuel-tech

try-with-resources는 무엇이고 언제 써야할까? 본문

programing-languages/Java

try-with-resources는 무엇이고 언제 써야할까?

여늘(yeonuel) 2024. 2. 25. 21:50

 

jdk 1.7부터 try-with-resources 문이 추가되었다. 이는 try-catch-finally 문에서 입출력(I/O) 관련 클래스를 사용할 때 발생하는 문제점 때문에 추가되었다. 일단, try-catch-fianlly 문에서 입출력(I/O) 관련 클래스를 사용할 때의 문제점부터 살펴보자.

 

1. 코드가 난잡해진다


try {
	// 입출력(I/O) 클래스
    fis = new FileInputStream("fileName.text");
    dis = new DataInputStream(fis);
} catch (IOException e) {
    e.printStackTrace();
} finally {
	// 사용한 자원 반환하기
    try {
        if (dis != null) {
        	// close() 호출하여 사용한 자원 반환
            dis.close();
        }
        // close() 메서드에서 IOException 발생할 수 있음
        // 즉, try-catch 문으로 처리해야함
    } catch (IOException e) {
        e.printStackTrace();;
    }
}

 

왜 이렇게 난잡해질까? 그 이유는 close()메서드에서는 IOException 예외가 발생할 수 있기 때문에

finally 문에서 또 다시 try-catch 문으로 예외 처리를 해줘야한다. 밑에는 close() 메서드의 선언부이다. 사진과 같이 throws로 IOException 예외를 던지는 것을 확인할 수 있다

하지만 이 보다 더 심각한 문제는 밑에 있다.

2. 에러 스택 트레이스가 누락된다

일단 밑에 코드를 간단하게 설명하면, MyResources 클래스에서는 2 가지 메서드를 지원하고 있고

둘 다 RuntimeException을 고의적으로 발생시켰다.즉, try 문에서 예외가 발생하고 finally 문에서 예외가 발생하고 있다.


class MyResources implements AutoCloseable {

    @Override
    public void close() throws RuntimeException {
        System.out.println("call close()");
        System.out.println();
        throw new IllegalStateException("close()에서 런타임 예외 발생시킴"); // RuntimeException 발생
    }

    public void use() {
        System.out.println("call use()");
        throw new IllegalStateException("use()에서 런타임 예외 발생시킴"); // RuntimeException 발생
    }
}



public class Main {

    public static void main(String[] args) {
        MyResources ms = null;

        try {
            ms = new MyResources();
            ms.use(); // 고의적으로 RuntimeException 발생 1
        } finally {
            if (ms != null) {
                ms.close(); // 고의적으로 RuntimeException 발생 2
            }
        }
    }

}

 

 

콘솔에서 에러 스택 트레이스를 확인하면 try문의 예외가 무시된 것을 확인할 수 있다. 바로 try 블러과 finally 블럭에서 모두 예외가 발생하면 try 블럭의 예외가 무시된다는 것이다. 이는 에러 스택 트레이스가 누락되어 디버깅하기 어려워진다.

 

따라서 이러한 문제점을 보완하기 위해 try-with-resouces 문이 추가되었다. 이제는 try-with-resources 문을 적용하여 문제가 어떻게 해결되는지 확인해보자.

 



class MyResources implements AutoCloseable {

    @Override
    public void close() throws RuntimeException {
        System.out.println("call close()");
        System.out.println();
        throw new IllegalStateException("close()에서 런타임 예외 발생시킴"); // RuntimeException 발생
    }

    public void use() {
        System.out.println("call use()");
        throw new IllegalStateException("use()에서 런타임 예외 발생시킴"); // RuntimeException 발생
    }
}



public class Main {

    public static void main(String[] args) {
        try (MyResources ms = new MyResources()) {
             ms.use();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

 

try-with-resources 문에서 객체를 자동 close() 해주려면 해당 객체는 AutoCloseable 인터페이스를 구현해야한다. AutoCloseable 인터페이스는 Closeable의 자식 인터페이스이므로 Closeable 인터페이스를 구현했으면 자동으로 close() 메서드를 호출할 수 있다. 이는 기존에 Closeable로 구현된 클래스도 변경 없이 try-with-resources 문을 사용하기 위함이다.

 

 

코드가 깔끔해지고 에러 스택 트레이스가 누락되지 않는 것을 확인할 수 있다. try-with-resources 문의 괄호안에 객체를 생성하면 이 객체는 자동으로 close()가 호출된다. 그리고 일반적인 예외와 close()에서 예외가 동시에 발생하면 일반적인 예외에 대한 내용이 출력되고 close()에서 발생한 예외는 '억제된(suppressed)'로 출력되는 것을 확인할 수 있다. 즉, 실제 발생한 예외를 보여주고 close()에서 발생한 예외는 억제된 예외로 다룬다. 

 

 

 

결론적으로 try-with-resources는 try()문에 생성된 입출력(I/O) 클래스의 close() 메서드를 자동호출 해주고 예외를 적절히 처리해준다. 따라서, 입출력(I/O) 클래스를 사용할 때는 try-with-resources를 활용하여 깔끔한 코드 작성과 에러 스택 트레이스 누락 문제를 방지하자

 

 

 

- 참고

1. 망나니 개발자님 블로그

https://mangkyu.tistory.com/217

 

[Java] try-with-resources란? try-with-resources 사용법 예시와 try-with-resources를 사용해야 하는 이유

이번에는 오랜만에 자바 문법을 살펴보고자 합니다. Java7부터는 기존의 try-catch를 개선한 try-with-resources가 도입되었는데, 왜 try-catch가 아닌 try-with-resources를 사용해야 하는지, 어떻게 사용하는지

mangkyu.tistory.com

 

2. 자바의 정석(남궁성)

Java의 정석 | 남궁성 - 교보문고 (kyobobook.co.kr)

 

Java의 정석 | 남궁성 - 교보문고

Java의 정석 | 자바의 기초부터 실전활용까지 모두 담다!자바의 기초부터 객제지향개념을 넘어 실전활용까지 수록한『Java의 정석』. 저자의 오랜 실무경험과 강의한 내용으로 구성되어 자바를

product.kyobobook.co.kr