[JAVA] try-with-resources 써야 돼?

nick·2024년 3월 15일
0

JAVA

목록 보기
6/13

try-with-resource란?

  • java 7에서 도입된 try-catch-finally를 개선한 문법

💡 try-catch-finally

  • 사용 후 반납해야 할 자원들은 Closeable 인터페이스를 구현했고, 무조건 사용 후에 close() 메서드를 호출해야 한다
  • 호출하지 않으면 거의 장애 발생!!!

🤦‍♂️ 문제점

  • 개발자가 실수로 close() 호출하지 않으면 바로 문제 발생 ⇒ 이를 해결하고자 나온 문법이 try-with-resources임

💡 try-with-resources

  • AutoCloseable 인터페이스를 구현한 클래스에 대해서 자동으로 자원을 반납해주는 기능 제공

❓ 그럼 기존 Closeable 구현한 클래스들은 적용이 안되나…?

  • AutoCloseable 인터페이스를 기존 Closeable 인터페이스의 부모 인터페이스로 추가했다는 점

  • 만약 Closeable의 자식으로 AutoCloseable을 만들었다면, try-with-resouces를 적용하기 위해서는 기존의 Closeable 인터페이스를 구현한 모든 클래스들을 AutoCloseable 인터페이스를 구현하도록 수정해야 함

  • 반대로 기존에 있던 CloseableAutoCloseable의 자식 인터페이스가 되어서 따로 수정할 필요가 없이 100% 호환 가능

try-catch-finally 말고 try-with-resources를 사용해라

1. try-catch-finally은 에러 스택 트레이스가 누락될 수 있다

  • 에러 stack trace가 누락되면 디버깅 및 에러 원인 파악이 매우 어렵다

예시 코드

public class Resource implements AutoCloseable {

    @Override
    public void close() throws RuntimeException{
        System.out.println("close");
        throw new IllegalStateException();
    }

    public void hello() {
        System.out.println("hello");
        throw new IllegalStateException();
    }
}

➡ try-catch-finally로 반납하는 경우

  • error stack trace 누락!!!
public class ResourceTest {
    public static void main(String[] args) {
        ResourceTest srcTest = new ResourceTest();
        srcTest.test1();
    }

    public void test1() {
        Resource rsc = null;

        try {
            rsc = new Resource();
            rsc.hello();
        } finally {
            if (rsc != null) {
                rsc.close();
            }
        }
    }
}

==결과==
Exception in thread "main" hello
java.lang.IllegalStateException
close
	at org.delivery.api.example.Resource.close(Resource.java:8)
	at org.delivery.api.example.ResourceTest.test(ResourceTest.java:17)
	at org.delivery.api.example.ResourceTest.main(ResourceTest.java:6)
  • Resource.java:8close() 메서드에서 발생한 예외다
  • ResourceTest.java:17finally에서 rsc.close()에서 발생한 예외다
  • rsc.hello()에서 발생한 IllegalStateException에 대한 예외 trace는 누락됐다

➡ try-with-resources로 반납하는 경우

  • trace 누락되지 않는다!!!
public void test2() {
    try (Resource rsc = new Resource()) {
        rsc.hello();
    }
}

==결과==
> Task :api:ResourceTest.main() FAILED
hello
close

Exception in thread "main" java.lang.IllegalStateException
	at org.delivery.api.example.Resource.hello(Resource.java:13)
	at org.delivery.api.example.ResourceTest.test2(ResourceTest.java:25)
	at org.delivery.api.example.ResourceTest.main(ResourceTest.java:7)
	Suppressed: java.lang.IllegalStateException
		at org.delivery.api.example.Resource.close(Resource.java:8)
		at org.delivery.api.example.ResourceTest.test2(ResourceTest.java:24)
		... 1 more
  • hello()close() 모두에 대해서 stack trace가 남는다

2. 누락 없이 모든 자원을 반납하려면 try-with-resources 써라

try-catch-finally

  • 자원 반납 누락될 수 있음
public void test3() {
    Resource rsc1 = null;
    Resource rsc2 = null;
    try {
        rsc1.hello();
        rsc2.hello();
    } finally {
        if (rsc1 != null) {
            rsc1.close();
        }

        if (rsc1 != null) {
            rsc1.close();
        }
    }
}
  • rsc1.close() 하는 경우에도 IllegalStateException 발생하지만, rsc2도 반납될 거라고 생각함
  • 하지만 rsc2는 정상적으로 반납되지 않는다.
  • 왜냐하면 rsc1.close() 예외가 발생 → 이 부분을 또 try-catch-finally로 묶어줘야 함

➡ try-with-resources

  • 모든 자원 자동 반납
public void test4() {
    try (Resource rsc1 = new Resource(); Resource rsc2 = new Resource()) {
        rsc1.hello();
        rsc2.hello();
    }
}

== 결과 ==
> Task :api:ResourceTest.main() FAILED
hello
close
close
  • 결과에서 볼 수 있듯이 정상적으로 rsc1, rsc2 모두 close 된 것을 확인할 수 있다

❓ 어떻게 자동 반납되는지?

  • java file → class file로 컴파일 될 때, try-with-resources에서 누락없이 모든 부분try-catch-finally로 컴파일러가 변환을 해준다
  • ⭐ 우리가 직접 try-catch-finally 쓰지 말고, 컴파일러가 누락 없이 처리하도록 우리는 try-with-resources를 쓰자

‼ [정리] 반드시 try-with-resources를 써야하는 이유

  1. 코드 간결
  2. 자원 반납 자동
  3. 실수, 에러로 자원 반납 못한 경우 방지
  4. stack trace를 누락하지 않고 남길 수 있음
profile
티스토리로 이전 : https://andantej99.tistory.com/

0개의 댓글