-
아이템8. finalizer와 cleaner 사용을 피하라Java/이펙티브 자바 2023. 6. 4. 17:10
핵심정리
- finalizer와 cleaner는 즉시 수행된다는 보장이 없다.
- finalizer와 cleaner는 실행되지 않을 수도 있다.
- finalizer 동작 중에 예외가 발생하면 정리 작업이 처리되지 않을 수도 있다.
- finalizer와 cleaner는 심각한 성능 문제가 있다.
- finalizer는 보안 문제가 있다.
- 반납할 자원이 있는 클래스는 AutoCloseable을 구현하고 클라이언트에서 close()를 호출하거나 try-with-resourse를 사용해야 한다.
* finalizer는 객체 생성하기 바빠서 finalizer 큐에 들어있는 레퍼런스를 제 때 GC해주기 어렵다
* finalizer와 cleaner는 권장하지 않는다.
* autoclosable과 try-resource를 권장한다.
* cleaner를 안전망으로 사용할 수 있다. - 사용자가 try-resource를 안쓰는 경우를 대비해서..활용
완벽공략
- p42, Finalizer 공격
- p43, AutoClosable
- p45, 정적이 아닌 중첩 클래스는 자동으로 바깥 객체의 참조를 갖는다.
- p45, 람다 역시 바깥 객체의 참조를 갖기 쉽다.
완벽공략 22 - Finalizer 공격
: 만들다 만 객체를 finalize 메소드에서 사용하는 방법
- Finalizer 공격
public class BrokenAccount extends Account { public BrokenAccount(String accountId) { super(accountId); } @Override protected void finalize() throws Throwable { this.transfer(BigDecimal.valueOf(100), "test"); } }
ㆍ예외 처리에 걸리기전에 gc 되면서 finalize 실행 - transfer 실행, 예외처리 걸린 계정이라도 로직 수행가능
- 방어하는 방법
ㆍfinal 클래스로 만들거나
public final class Account {...}
ㆍfinalizer() 메소드를 오버라이딩 한 다음 final을 붙여서 하위 클래스에서 오버라이딩 할 수 없도록 막는다.
public class Account { private String accountId; public Account(String accountId) { this.accountId = accountId; if(accountId.equals("test")) { throw new IllegalArgumentException("test은 계정을 막습니다."); } } public void transfer(BigDecimal amount, String to) { System.out.printf("transfer %f from %s to %s\n", amount, accountId, to); } @Override protected final void finalize() throws Throwable { } }
완벽공략 23 - AutoClosable
: try-with-resource 를 지원하는 인터페이스
- void close() throws Exception
ㆍ인터페이스에 정의된 메서드에서 Exception 타입으로 예외를 던지지만
ㆍ실제 구현체에서는 구체적인 예외를 던지는 것을 추천하며
@Override public void close() throws IOException { reader.close(); }
public class App { public static void main(String[] args) { try(AutoClosableIsGood good = new AutoClosableIsGood("")) { //TODO 자원 반납 처리가 됨. } catch (Exception e) { e.printStackTrace(); } } }
ㆍ가능하다면 예외를 던지지 않는 것도 권장한다.
@Override public void close() { try { reader.close(); } catch (IOException e) { // logging or throw new RuntimeException(e); } }
ㆍidempotent을 권장한다. - 몇 번을 실행하던 같은 결과가 발생해야 한다.
- Closeable 클래스
ㆍIOException을 던지며 - 던질거면 IOException 계열을 던져야한다.
ㆍ반드시 idempotent 해야 한다. - 몇 번을 실행하던 같은 결과가 발생해야 한다.
'Java > 이펙티브 자바' 카테고리의 다른 글
아이템10. equals는 일반 규약을 지켜 재정의하라 (0) 2023.06.07 아이템9. try-finally 보다 try-with-resources 를 사용하라. (0) 2023.06.07 아이템7. 다 쓴 객체 참조를 해제하라. (0) 2023.06.01 아이템6. 불필요한 객체 생성을 피하라 (0) 2022.11.10 아이템5. 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 (0) 2022.11.01