https://www.itworld.co.kr/news/224419

몇 년 간의 무성한 소문 끝에 마침내 자바가 JDK 18에서 finalize 메서드를 퇴역시킬 준비를 하고 있다. JDK 향상 제안(Enhancement Proposal) 421은 finalize를 사용 중단되는 요소로 명시하고, 테스트를 위해 이 메서드를 비활성화하는 것을 허용한다. 기본적으로는 계속 활성화된 상태로 유지되다가 이후 릴리스에서 완전히 제거된다. finalize의 끝이 무엇을 의미하는지, 이제부터는 오류와 리소스 클린업을 어떻게 처리해야 하는지 알아보자.

ⓒ Getty Images Bank

finalize란 무엇인가

finalize가 왜 사라지는지, 그 대신 무엇을 사용해야 하는지를 이해하기 전에 finalize가 무엇인지부터 살펴보자. finalize의 기본적인 개념은 객체가 가비지 수집 대상이 될 때 실행되는 메소드를 객체에 정의할 수 있도록 하는 것이다. 기술적으로 객체는 [팬텀 도달 가능(phantom reachable)](http://www.cs.fsu.edu/~jtbauer/cis3931/tutorial/refobjs/about/phantom.html#:~:text=An object is phantomly reachable,been finalized%2C but not reclaimed.) 상태가 될 때, 즉 JVM에 강하거나 약한 참조가 남아 있지 않을 때 가비지 수집 대상이 된다. 이 시점에서 JVM이 object.finalize() 메서드를 실행하고 애플리케이션별 코드가 I/O 스트림이나 데이터스토어에 대한 핸들과 같은 리소스를 클린업한다는 개념이다.

자바의 루트 Object 클래스에는 equals(), hashCode() 등 다른 메소드와 함께 finalize() 메소드가 있다. 이 메소드의 용도는 모든 자바 프로그램이 만든 모든 단일 객체가 리소스 누출을 방지하기 위한 이 단순한 메커니즘에 참여할 수 있도록 하는 것이다. 예외가 발생하고 다른 클린업 코드가 누락된 경우에도 해당된다. 즉, 객체는 여전히 가비지 수집 대상으로 표시되고 최종적으로는 해당 객체의 finalize 메소드가 호출된다. 문제가 해결된 것이다. 그렇지 않은가? 리소스를 소비하는 객체에서 finalize() 메소드를 오버라이드하기만 하면 된다.

finalize 메소드의 문제

거기까지는 개념이다. 그러나 현실은 전혀 다르다. finalize에는 클린업 유토피아의 현실화를 막는 여러 단점이 있다. 이런 상황은 이론적으로는 좋아 보이지만 실제로 사용할 때 여러 문제를 일으킨다는 면에서 serialize() 메소드와 비슷하다. finalize의 문제점은 다음과 같다.

finalize가 사라진 이후

finalize 메소드가 퇴출된 이후 오류 처리와 클린업을 위한 적절한 방법은 무엇일까? 3가지 대안이 있다. try-catch-finally 블록, try-with-resource 문, 그리고 클리너(cleaner)다. 각 방법마다 장단점이 있다.

try-catch-finally 블록 : 리소스 해제를 처리하는 오래된 방법으로 try-catch 블록이 있다. 여러 상황에서 사용할 수 있는 방법이지만 오류가 빈번하고 장황하다는 단점이 있다. 예를 들어 중첩된 오류 조건(즉, 리소스 닫기 역시 예외를 유발하는 경우)을 완전히 캡처하려면 <리스트 1>과 같은 코드가 필요하다.