[JAVA] try-finally 쓰지 마세요

1 minute read

요약

finallydeprecate될 예정입니다.
향후 릴리스에서는 기본적으로 비활성화되며, 이후 릴리스에서는 제거될 예정입니다.
finally를 사용하는 라이브러리 및 애플리케이션의 유지 관리자는 try-with-resourcescleaners와 같은 다른 리소스 관리 기법으로 마이그레이션해야 합니다.

finally의 위험성: 리소스 누수

파일 디스크립터(File descriptor)나 네이티브 메모리 블록(Native memory block)과 같이 운영 체제에서 제공하는 리소스를 사용하는 객체가 있습니다.
이러한 객체의 경우 단순히 객체의 메모리를 회수하는 것만으로는 충분하지 않으며, 프로그램은 일반적으로 객체의 close와 같은 메서드를 호출하여 기본 리소스를 운영 체제에 다시 릴리스해야 합니다.
GC가 객체를 회수하기 전에 프로그램이 이 작업을 수행하지 못하면 리소스를 해제하는 데 필요한 정보가 손실됩니다.
운영 체제에서 여전히 사용 중인 것으로 간주되는 리소스에 누수가 발생한 것입니다.

아래 코드는 한 파일에서 다른 파일로 데이터를 복사합니다.
복사하는 동안 예외가 발생하더라도 리소스가 해제되도록 try-finally 구문을 사용했습니다.

FileInputStream  input  = null;
FileOutputStream output = null;
try {
    input  = new FileInputStream(file1);
    output = new FileOutputStream(file2);
    // ... copy bytes from input to output ...
    output.close();  output = null;
    input.close();   input  = null;
} finally {
    if (output != null) output.close();
    if (input  != null) input.close();
}

이 코드는 잘못되었습니다. 복사가 예외를 발생시키고 finally 블록의 output.close()에서 예외를 발생하면 input 스트림이 유출됩니다.
이를 막기 위해서는 중첩된 try-finally를 사용해야 하는데, 가능한 모든 실행 경로에서 예외를 처리하는 것은 힘들고 제대로 처리하기 어렵습니다.

그 외에도 finally에는 여러 결함이 있습니다.
해당 부분에 대해서는 참고를 참고하십시오.

finally의 대안: try-with-resources

try (FileInputStream input = new FileInputStream(file1);
     FileOutputStream output = new FileOutputStream(file2)) {
    // ... copy bytes from input to output ...
}

Java 7은 try-finally 구문을 개선하기 위해 try-with-resources를 도입했습니다.
try-with-resources를 사용하면 예외 발생 여부에 관계없이 해당 메서드의 close() 메서드 호출이 보장되는 방식으로 리소스를 사용할 수 있습니다.

finally의 대안: Cleaner

Cleaner는 잘 안 사용해봐서 모르겠으나 Cleaner를 사용하는 방법도 있습니다.
그런데 Effective Java에서는 Cleaner를 사용하지 말라고 되어있는 것 같습니다?(읽어보진 않음)

참고

Categories:

Updated:

Comments