티스토리 뷰
728x90
반응형
try-finally 보다는 try-with-resources를 사용하라
자바 라이브러리에는 close 메서드를 호출해 직접 닫아줘야 하는 자원이 많습니다. InputStream, OutputStream, java.sql.Connection 등이 좋은 예입니다. 사용한 자원을 닫아주는 것은 클라이언트가 놓치기 쉬워서 예측할 수 없는 성능 문제로 이어지기도 합니다. 이런 자원 중 상당수가 안정망으로 finalizer를 사용하고는 있지만 Item08에서 본거처럼 그렇게 믿을만한 녀석은 아닙니다.
💡close() 메서드를 사용하여 자원 회수
- 구글링이나 많은 책에서 아래와 같은 코드를 심심치 않게 볼 수 있습니다. 지금까지 우리는 명시적으로 close() 메서드를 호출해왔었습니다.
- 아래 예제도 finally를 이용해 예외가 발생하더라도 안정적으로 자원을 닫아주고 있습니다.하지만 finally를 명시하지 않을 가능성도 존재할 수 있습니다.
public class StringUtils {
private BufferedReader reader;
public String firstLineOfFile(String path) throws IOException {
reader = new BufferedReader(new FileReader(path));
try {
return reader.readLine();
} finally {
reader.close();
}
}
}
💡자원이 둘 이상이라면?
- 코드의 가독성이 좋지 않은 것을 볼 수 있습니다.
- try-finally를 사용했지만 여기에도 문제가 있습니다. 기기에 물리적인 문제가 생긴다면 readLine() 메서드가 예외를 던지고, 같은 이유로 close() 메서드가 동작을 실패해 예외가 발생한다면 후자의 예외가 전자의 예외를 가려버리게 되어 스택 추적이 힘들어지고 디버깅도 어려워지게 됩니다.
public class StringUtils {
private BufferedReader reader;
public String firstLineOfFile(String path, String fileName) throws IOException {
reader = new BufferedReader(new FileReader(path));
try {
OutputStream outputStream = new FileOutputStream(fileName);
try {
String s = reader.readLine();
outputStream.write(s.getBytes(), 0, s.length());
} finally {
outputStream.close();
}
return reader.readLine();
} finally {
reader.close();
}
}
}
해결책
- 자바 7에서 등장한 try-with-resources를 사용하면 이러한 문제를 해결할 수 있습니다.
- try-with-resources를 사용하기 위해서는 해당 자원이 AutoCloseable 인터페이스를 구현해야합니다.
- AutoCloseable 인터페이스는 void를 반환하는 close() 메서드 하나만 덩그러니 정의한 인터페이스입니다. 자바 라이브러리와 서드파티 라이브러리들의 수많은 클래스와 인터페이스는 이미 AutoCloseable을 구현하거나 확장을해뒀습니다.
- 코드도 간결해지고 readLine()과 close()메서드 양쪽에서 예외가 발생한다면, close() 메서드에서 발생한 예외는 숨겨지고 readLine() 메서드에서 발생한 예외만 기록됩니다.
public class StringUtils {
public String firstLineOfFile(String path, String fileName) {
try(BufferedReader reader = new BufferedReader(new FileReader(path))) {
FileOutputStream fileOutputStream = new FileOutputStream(fileName);
String s = reader.readLine();
fileOutputStream.write(s.getBytes(), 0, s.length());
return s;
} catch (IOException e) {
return e.getMessage();
}
}
}
try-with-resources Vs AutoCloseable
💡try-with-resources로 구현
public class StringUtils {
public String firstLineOfFile(String path, String fileName) {
try(FileOutputStream fileOutputStream = new FileOutputStream(path, true)) {
String strText = "안녕 세상!";
fileOutputStream.write(strText.getBytes());
return strText;
} catch (IOException e) {
e.printStackTrace();
return e.getMessage();
}
}
}
public class EffectiveJavaApplication {
public static void main(String[] args) {
StringUtils stringUtils = new StringUtils();
stringUtils.firstLineOfFile("/Users/디렉토리/text.txt");
}
}
💡AutoCloseable로 구현
- 나의 착각 - 필자는 AutoCloseable 인터페이스를 구현한 후 close 메서드만 덩그러니 있으면 될 줄 알았는데 그게 아니라 해당 메서드에서 사용한 객체를 close 해줘야한다는 것을 알게되었습니다.
public class StringUtils implements AutoCloseable {
private FileOutputStream fileOutputStream;
public String firstLineOfFile(String path) throws IOException {
fileOutputStream = new FileOutputStream(path, true);
String strText = "안녕 세상!";
fileOutputStream.write(strText.getBytes());
return strText;
}
// good
@Override
public void close() throws Exception {
if (fileOutputStream != null) fileOutputStream.close();
System.out.println("closed!!");
}
// bad
@Override
public void close() throws Exception {
System.out.println("closed!!");
}
}
public class EffectiveJavaApplication {
public static void main(String[] args) {
try (StringUtils stringUtils = new StringUtils()) {
stringUtils.firstLineOfFile("/Users/디렉토리/text.txt");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
💡결론
- 자원 회수가 필수적인 경우 try-with-resources를 사용하자. 코드는 더 짧고 분명해지고, 만들어지는 예외 정보도 훨씬 유용합니다.
- AutoCloseable보다는 try-with-resources를 사용하는게 부가적인 코드가 덜 들어가는 느낌이여서 try-with-resources를 쓰는게 좋은거 같습니다.
728x90
반응형
'스터디 > 이펙티브 자바' 카테고리의 다른 글
이펙티브 자바 - Item11. equals를 재정의하려거든 hashCode도 재정의하라. (0) | 2022.07.07 |
---|---|
이펙티브 자바 - Item10. equals는 일반 규약을 지켜 재정의하라. (0) | 2022.07.06 |
이펙티브 자바 - Item8. finalizer와 cleaner 사용을 피하라. (0) | 2022.07.03 |
이펙티브 자바 - Item7. 다 쓴 객체 참조를 해제하라. (0) | 2022.07.03 |
이펙티브 자바 - Item6. 불필요한 객체 생성을 피하라. (0) | 2022.07.02 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
TAG
- spring boot redisson destributed lock
- 공간 기반 아키텍처
- spring boot poi excel download
- redis sorted set으로 대기열 구현
- redis 대기열 구현
- spring boot redisson sorted set
- 서비스 기반 아키텍처
- pipe and filter architecture
- pipeline architecture
- 람다 표현식
- spring boot excel download paging
- spring boot excel download oom
- spring boot redisson 분산락 구현
- java userThread와 DaemonThread
- 자바 백엔드 개발자 추천 도서
- 트랜잭셔널 아웃박스 패턴 스프링부트
- 레이어드 아키텍처란
- 트랜잭셔널 아웃박스 패턴 스프링 부트 예제
- space based architecture
- redis sorted set
- service based architecture
- spring boot 엑셀 다운로드
- transactional outbox pattern spring boot
- spring boot redis 대기열 구현
- transactional outbox pattern
- java ThreadLocal
- @ControllerAdvice
- JDK Dynamic Proxy와 CGLIB의 차이
- polling publisher spring boot
- microkernel architecture
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
글 보관함