반응형

try-finally - 더 이상 자원을 회수하는 최선의 방책이 아니다.!

class sampleCode() {

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

    }
}

자원이 둘 이상이면 try-finally 방식은 너무 지저분하다!

static void copy(String src, String dst) throws IOException{
    InputStream in = new FileInputStream(src);
    try{
        OutputStream out = new FileOutputStream(dst);
        try{
            byte[] buf = new byte[BUFFER_SIZE];
            int n;
            while((n=in.read(buf))) >=0 )
                out.write(buf, 0, n);

        }finally{
            out.close();
        }

        }finally{
        in.close();
        }

}

물리적인 문제가 생긴다면 firstLineOfFile 메서드 안의 readLine 메서드가 예외를 던지고,
같은 이유로 close 메서드도 실패할 것이다.
이러한 상황이라면 두번째 예외가 첫 번째 예외를 완전히 삼겨 버림

try-with-resources - 자원을 회수하는 최선책

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

복수의 자원을 처리하는 try-with-resources 짧고 매혹적이다.

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);
        }
}

readLine과 close 호출 약쪽에서 예외가 발생하면, close에서 발생한 예외는 숨겨지고
readLine에서 발생한 예외가 기록됨

try-with-resouces를 catch 절과 함께 쓰는 모습

static String firstLineOfFile(String path,String defaultVal){
        try(BufferedReader br=new BufferedReader(
        new FileReader(path))){
            return br.readLine();
        }catch(IOException e){
            return defaultVal;
        }
}

정리

꼭 회수해야 하는 자원을 다룰 때는 try~finll 말고, try-with-resources를 사용하자
코드는 더 짧고 분명해지고, 만들어지는 예외 정보도 훨씬 유용함

728x90
반응형

회사 코드에 EntityManager를 사용하여 try~catch~finally를 사용하여 finally에서 해당 EntityManager 인스턴스를 close()하고 자원을 반납하고 있었습니다. 

하지만 이펙티브 자바에서는 [아이템 9. try-finally 대신 try-with-resources를 사용하라.] 라는 내용이 존재합니다. 

그래서 EntityManager를 try-with-resources로 리팩터링을 하려고 했지만, AutoClosable이 지원하지 않는다고 IDE에서 말해주고 있었습니다. 관련 글을 찾던 중 블로그에 해당 이슈는 오픈소스에 fix issue로 등록이 되어 있고 특정 버전 이후에 추가가 되었다고 합니다.

제가 회사에서 쓰는 java persistence-api 라이브러리는 2.x로 AutoClosable을 지원하지 않았고, 3.x대로 올라가면서 Jakarta Persistence API -> 3.1.0 지원하게 된것을 알게되었습니다.

EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("default");
try(EntityManager entityManager = entityManagerFactory.createEntityManager()){

}

 

package jakarta.persistence;

import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaDelete;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.CriteriaUpdate;
import jakarta.persistence.metamodel.Metamodel;
import java.util.List;
import java.util.Map;

public interface EntityManager extends AutoCloseable {
    void persist(Object var1);

    <T> T merge(T var1);

    void remove(Object var1);

해당 Jakarta Persistence API의 EntityManager 인터페이스를 보면 알 수 있듯이 해당 클래스는 AutoCloseable을 상속하고 있는 것을 알 수 있습니다.

public interface AutoCloseable {
    /**
     * Closes this resource, relinquishing any underlying resources.
     * This method is invoked automatically on objects managed by the
     * {@code try}-with-resources statement.
     *
     * <p>While this interface method is declared to throw {@code
     * Exception}, implementers are <em>strongly</em> encouraged to
     * declare concrete implementations of the {@code close} method to
     * throw more specific exceptions, or to throw no exception at all
     * if the close operation cannot fail.
     *
     * <p> Cases where the close operation may fail require careful
     * attention by implementers. It is strongly advised to relinquish
     * the underlying resources and to internally <em>mark</em> the
     * resource as closed, prior to throwing the exception. The {@code
     * close} method is unlikely to be invoked more than once and so
     * this ensures that the resources are released in a timely manner.
     * Furthermore it reduces problems that could arise when the resource
     * wraps, or is wrapped, by another resource.
     *
     * <p><em>Implementers of this interface are also strongly advised
     * to not have the {@code close} method throw {@link
     * InterruptedException}.</em>
     *
     * This exception interacts with a thread's interrupted status,
     * and runtime misbehavior is likely to occur if an {@code
     * InterruptedException} is {@linkplain Throwable#addSuppressed
     * suppressed}.
     *
     * More generally, if it would cause problems for an
     * exception to be suppressed, the {@code AutoCloseable.close}
     * method should not throw it.
     *
     * <p>Note that unlike the {@link java.io.Closeable#close close}
     * method of {@link java.io.Closeable}, this {@code close} method
     * is <em>not</em> required to be idempotent.  In other words,
     * calling this {@code close} method more than once may have some
     * visible side effect, unlike {@code Closeable.close} which is
     * required to have no effect if called more than once.
     *
     * However, implementers of this interface are strongly encouraged
     * to make their {@code close} methods idempotent.
     *
     * @throws Exception if this resource cannot be closed
     */
    void close() throws Exception;
}

 

https://k3068.tistory.com/98

 

왜? EntityManager는 AutoCloseable 구현하고 있지 않은가?

EntityManager는 쓰레드 간에 공유를 하지 않고 사용 후 바로 정리해야 한다고 한다. public void run(ApplicationArguments args) throws Exception { EntityManager em = entityManagerFactory.createEntityManager(); EntityTransaction transa

k3068.tistory.com

 

https://www.inflearn.com/questions/231224/entitymanager-%EB%8A%94-%EC%99%9C-autocloseable-%EC%9D%84-%EC%A7%80%EC%9B%90%ED%95%98%EC%A7%80-%EC%95%8A%EB%82%98%EC%9A%94

 

EntityManager 는 왜 AutoCloseable 을 지원하지 않나요? - 인프런 | 질문 & 답변

안녕하세요문득 궁금한점이 생겨서 질문해봅니다.항상 사용하고 버려야 한다면 AutoCloseable지원하여 try-with-resource 문을 사용할 수 있도록 도움을 주면 좋을 것 같다고 생각이 들었지만시용해볼

www.inflearn.com

 

728x90

+ Recent posts