[이펙티브 자바] Item08 완벽공략. AutoClosable
item08. finalizer와 cleaner 사용을 피하라.
" p43. AutoClosable "
AutoClosable이란?
: try-with-resources를 지원하는 인터페이스이다.
/*
* Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package java.lang;
/**
* An object that may hold resources (such as file or socket handles)
* until it is closed. The {@link #close()} method of an {@code AutoCloseable}
* object is called automatically when exiting a {@code
* try}-with-resources block for which the object has been declared in
* the resource specification header. This construction ensures prompt
* release, avoiding resource exhaustion exceptions and errors that
* may otherwise occur.
*
* @apiNote
* <p>It is possible, and in fact common, for a base class to
* implement AutoCloseable even though not all of its subclasses or
* instances will hold releasable resources. For code that must operate
* in complete generality, or when it is known that the {@code AutoCloseable}
* instance requires resource release, it is recommended to use {@code
* try}-with-resources constructions. However, when using facilities such as
* {@link java.util.stream.Stream} that support both I/O-based and
* non-I/O-based forms, {@code try}-with-resources blocks are in
* general unnecessary when using non-I/O-based forms.
*
* @author Josh Bloch
* @since 1.7
*/
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;
}
AutoClosable 은 close 메서드 하나만을 가진 인터페이스이지만 그렇다고 함수형 인터페이스는 아니다. (그럴 목적으로 만든 인터페이스가 아님)
그리고 close 메서드는 Exception 에러를 던지고 있다.
try-with-resources를 지원하는 인터페이스라는 것은 즉 자원해제를 할 때 사용되는 인터페이스로
자원 해제되길 바라는 클래스라면 AutoCloseable을 implement해서 구현해주면 된다.
public class AutoClosableIsGood implements AutoCloseable{
private BufferedInputStream inputStream;
@Override
public void close(){
// idempotent 해야 한다.(몇번을 호출하더라도 동일한 결과가 수행되어야 한다.) AutoClosable 은 권장, Closeable 필수
try {
inputStream.close();
} catch (IOException e) {
throw new RuntimeException("failed to close " + inputStream);
}
}
}
그리고 여기서 BufferedInputStream을 사용하고 있기 때문에 IOException이 발생할 확률이 있기 때문에 Exception 보다 구체적인 IOException을 잡아줬다. 이렇게 여기서 예외를 잡고 런타임 예외로 변환해서 던져주면 클라이언트 코드에서 예외 처리를 안해줘도 되기 때문에 이 방법을 권장한다.
public class App {
public static void main(String[] args) {
try (AutoClosableIsGood good = new AutoClosableIsGood()){
// TODO 자원 반납 처리가 됨
}
}
}
그리고 클라이언트 코드에서는 이런식으로 사용해주면 된다.
Closable
: AutoClosable을 구현한 인터페이스
AutoClosable보다 좀 더 구체적인 클래스로 AutoCloseable은 Exception을 던지는 반면, Closeable은 IOException을 던진다.
그리고 AutoCloseable은 idempotent를 권장하지만, Closeable은 반드시 idempotent 해야 한다.
❓idempotent란?
번역하면 '멱등성' 이라고 좀 더 어려운말로 번역되는데 ..
연산을 여러 번 적용하더라도 결과가 달라지지 않는 성질, 연산을 여러 번 반복하여도 한 번만 수행된 것과 같은 성질을 의미한다.