try-finally보다는 try-with-resources를 사용하라
자바에는 InputStream, OutputStream, BufferedReader, java.sql.connection과 같이 close 메서드를 호출하여 직접 닫아줘야하는 자원들이 많다.
하지만 이러한 자원들은 사용 후 close 메서드를 호출하지 않는다면 예측할 수 없는 성능 문제로 이어지기도 한다.
이러한 자원 중 상당수가 close 메서드가 호출되지 않았을때 방안으로 finalizer를 활용하고는 있지만 finalizer같은 경우에는 호출 시점이 불명확해 믿을만하지 못하다.
try-finally
전통적으로 자원이 제대로 닫힘을 보장하는 수단으로 try-finally문을 쓰였다.
예외가 발생하거나 메서드에서 반환되는 경우를 포함한다
static String firstLineOfFile(String path) throws IOException {
BufferedReader br = new BufferedReader(new FileReader(path));
try {
return br.readLine();
} finally {
br.close();
}
}
하지만 신경 써줘야 할 자원이 둘 이상이면 코드가 길어져 복잡해지고 또 다른 문제점이 있다.
static void copy(String src, String dst) throws IOException {
InputStream in = new FileInputStream(src);
try {
OutputStream out = new FileOutputStream(dst);
try {
byte[] buf = new byte[BUFFER_SIZE];
int n;
while ((n = in.read(buf)) >= 0) out.write(buf, 0, n);
} finally {
out.close();
}
} finally {
in.close();
}
}
해당 코드는 read부분에서 에러가 발생하면 에러가 터지고 finally에서 close시 또 다시 에러가 발생한다.
이런 경우가 발생한다면 두번째에 나타나는 에러가 첫번째 에러를 삼켜버려 디버깅이 힘들어진다.
try-with-resources
위 문제점은 try-with-resources문을 사용하여 간편하게 해결 할 수 있다.
static void copy(String src, String dst) throws IOException {
try (InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dst)) {
byte[] buf = new byte[BUFFER_SIZE];
int n;
while ((n = in.read(buf)) >= 0) out.write(buf, 0, n);
}
}
finally를 통해 close 메서드를 호출하지않아도 작업이 끝나면 알아서 close 메서드를 호출해줘 실수를 방지할 수 있고 코드가 간결해진다.
또 위처럼 try 안에서 에러가 발생하고 close 호출시 에러가 발생했을때 첫번째 에러만 기록이되 두번째 에러(close 호출시 에러)가 숨겨졌다는 suppressed라는 꼬리표를 달고 에러를 출력한다.
try-with-resources 사용법
try-with-resources는 위에 try-finally와 크게 다르지않다.
다르다하면 close() 메소드를 호출 할 것들을 try문 ()에서 생성해주면된다.
try-with-resources는 예외처리 까지 마치면 인스턴스들의 close() 메소드를을 알아서 호출한다.
try-with-resources 주의 사항
try()안에서 선언한 구현체(객체)가 close() 메서드를 가지고 있다해도 모두 동작하는것은 아니다.
java.io.Closeable 인터페이스를 이용해 구현된 구현체에게만 적용된다.
그래서 본인이 구현한 구현체가 close()메서드를 호출해주고싶다면 해당 인터페이스를 이용해 구현해줘야한다.
AutoCloseable 사용
try-with-resources 사용시 java.lang.AutoCloseable.java 혹은 Closeable 인터페이스를 이용해 구현체를 구현해야한다.
package com.example.springsecurity.config;
public class Abc implements AutoCloseable{
@Override
public void close() throws Exception {
System.out.println("close method!");
}
public void doSomething() {
System.out.println("do something");
}
}
public class Main {
public static void main(String[] args) throws IOException {
try(Abc abc = new Abc()) {
abc.doSomething();
}
}
}
// do something
// close method
'book review > Effective java' 카테고리의 다른 글
[Effective Java] Item 11. equals를 재정의하려거든 hashCode도 재정의 해라 (0) | 2024.03.18 |
---|---|
[Effective Java] Item 10. equals는 일반 규약을 지켜 재 정의하라 (0) | 2024.03.11 |
[Effective Java] Item 8. finalizer와 cleaner 사용을 피하라 (0) | 2024.02.13 |
[Effective Java] Item 7. 다 쓴 객체 참조를 해제하라 (1) | 2024.02.07 |
[Effective Java] Item 6. 불필요한 객체 생성을 피하라 (0) | 2024.02.06 |