ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 아이템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 해야 한다. - 몇 번을 실행하던 같은 결과가 발생해야 한다.

    댓글

Designed by Tistory.