9. try-finally보다는 try-with-resources를 사용하라
Effective Java의 아이템 9는 "try-finally 보다는 try-with-resources를 사용하라"라는 주제로, 자원 관리를 보다 안전하고 효율적으로 처리하는 방법에 대해 다룹니다. 주로 자원을 자동으로 관리하는 방법에 관한 내용으로, try-with-resources
구문을 사용해야 하는 이유와 그 장점을 설명합니다.
주요 내용:
try-finally
의 한계:try-finally
블록을 사용하여 자원을 해제하는 전통적인 방법은 매우 흔한 패턴입니다. 예를 들어, 파일이나 네트워크 연결 등의 자원을 닫는 데 사용됩니다.하지만 이 방식에서는 예외가 발생할 경우, 자원을 안전하게 닫지 못하는 경우가 발생할 수 있습니다. 예외가 발생한 후 자원을 닫는 작업을
finally
블록에서 수행하는데, 자원을 닫는 도중 또 다른 예외가 발생하면 두 번째 예외가 첫 번째 예외를 덮어쓰게 되어 중요한 정보를 놓치게 됩니다.
try-with-resources
:try-with-resources
구문은 자원 관리에 있어 더 안전하고 깔끔한 방법을 제공합니다. 자원을 관리하는 객체는AutoCloseable
인터페이스를 구현해야 합니다. 이 인터페이스는close()
메서드를 정의하여 자원을 해제하는 방법을 제공하고,try-with-resources
블록 내에서 이 자원들이 자동으로 닫히게 합니다.try-with-resources
를 사용하면 예외가 발생하더라도 자원은 자동으로 닫히며, 여러 자원이 있을 경우 순서대로 닫힙니다. 또한, 예외가 여러 개 발생할 경우try-with-resources
구문은 모든 예외를 처리하여 예외가 덮어쓰여지지 않도록 합니다.
AutoCloseable
인터페이스:자원을 닫는 작업을 자동으로 수행하려면 해당 객체가
AutoCloseable
인터페이스를 구현해야 합니다. 이 인터페이스는close()
메서드를 정의하며, 자원을 닫는 데 필요한 작업을 수행합니다. 예를 들어,InputStream
,OutputStream
,Connection
등이 이 인터페이스를 구현하고 있습니다.
try-with-resources
의 장점:간결함:
try-with-resources
는 자원 해제를 자동으로 처리하므로, 개발자가finally
블록을 작성할 필요가 없습니다. 코드가 더 간결하고 읽기 쉬워집니다.안전성: 예외가 발생하더라도 자원 해제를 보장합니다. 자원 해제 중에 예외가 발생해도, 발생한 예외들을 모두 추적할 수 있습니다.
효율성: 자원을 제대로 닫지 않아 발생할 수 있는 리소스 누수 문제를 방지할 수 있습니다.
finally
와의 차이점:finally
를 사용하는 방식에서는 자원 해제 중 예외가 발생하면 원래 발생한 예외를 덮어쓸 수 있습니다. 이는 중요한 예외 정보를 놓치게 만들 수 있습니다. 반면,try-with-resources
는 자원 해제 중 발생한 예외를 모두 기록하여 놓치지 않도록 합니다.
예시 코드:
try-finally
방식 (옛 방식):
public void readFile(String filePath) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(filePath));
// 파일을 읽는 작업
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
try-with-resources
방식 (추천 방식):
public void readFile(String filePath) {
try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
// 파일을 읽는 작업
} catch (IOException e) {
e.printStackTrace();
}
}
분석:
간결성:
try-with-resources
는 자원을 자동으로 닫아주기 때문에,finally
블록을 작성할 필요가 없어 코드가 더 간결해집니다. 이는 코드의 유지보수성과 가독성을 크게 향상시킵니다.안전성:
try-with-resources
는 여러 자원을 관리할 때, 자원 닫기 중 예외가 발생해도 이를 누락하지 않고 모두 처리합니다. 또한, 예외 처리에 있어 예외가 덮어쓰이지 않도록 예외들을 모두 기록할 수 있어 문제를 더 잘 추적할 수 있습니다.자원 누수 방지: 자원이 자동으로 닫히므로, 자원 누수 문제를 예방할 수 있습니다.
finally
에서 자원을 수동으로 닫는 방식은 실수로 자원을 닫지 않거나 예외를 놓칠 수 있지만,try-with-resources
는 이를 방지합니다.
결론:
Effective Java 아이템 9에서 추천하는 try-with-resources
는 코드의 안전성과 효율성을 높이는 중요한 패턴입니다. 자원 해제를 명시적으로 처리하는 finally
블록 대신, 자원을 자동으로 관리하는 try-with-resources
구문을 사용함으로써 코드가 더 안전하고 간결해지며, 예외 발생 시 자원 누수나 예외 덮어쓰기를 방지할 수 있습니다.
추가 고려 사항
Suppressing Exceptions (addSuppressed)
try-with-resources를 사용하여 자원을 닫는 과정에서 기록된 발생한 예외(Suppressed Exception)는 Throwable.getSuppressed() 메서드를 사용하여 확인할 수 있습니다. 예를 들면:
public void testSuppressedException() {
try (MyResource res = new MyResource()) {
throw new RuntimeException("Primary Exception");
} catch (Exception e) {
System.out.println("Caught: " + e.getMessage());
for (Throwable suppressed : e.getSuppressed()) {
System.out.println("Suppressed: " + suppressed.getMessage());
}
}
}
class MyResource implements AutoCloseable {
@Override
public void close() {
throw new RuntimeException("Closing Exception");
}
}
위 코드에서 Primary Exception이 발생한 후, close()에서 또 다른 예외(Closing Exception)가 발생합니다.
try-finally에서는 Closing Exception이 Primary Exception을 덮어쓰지만, try-with-resources에서는 Closing Exception이 Suppressed Exception으로 저장됩니다.
Last updated