븟츠의 try-finally 보다는 try-with-resources를 사용하자!

2024. 7. 28. 00:42·Java
목차
  1. 들어가며
  2. 그냥 단순히 close를 해주면 문제가 생길 수 있다!
  3. 그런데 만약, close를 여러번 호출해야 하는 상황이 온다면..?
  4. try-with-resource 가 뭔데?
  5. 그래서 어떻게 사용하는데?

들어가며

자바 라이브러리 중에는 close 메서드를 호출해 직접 닫아주어야 하는 자원이 많다.
InputStream, OutputStream, java.sql.Connection 등이 있는데, 자원 닫기는 클라이언트(여기서의 클라이언트는 우리 코드를 직접 작성해야하는 개발자이다)가 놓치기 쉬워서 예측할 수 없는 성능 문제로 이어지기도 하니 주의해야한다.
이런 자원 중 상당수가 안전망으로 finalizer를 활용하고는 있지만, finalizer는 그리 믿을만 하지 못하다.
finalizer에 대해서 알아보기 전에, close에 대해서 간단하게 알아보자.

 

그냥 단순히 close를 해주면 문제가 생길 수 있다!

보통 나는 지금까지 close 를 사용하면 아래 코드처럼 사용하였는데.. 이는 잘못된 사용방법이다.

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String s = br.readLine();
br.close();

 

물론 다른 방법으로 BufferedReader 사용 중 IOException 이 발생하게 되면, 메서드가 종료되므로 close가 호출되지 않고 스트림이 메모리에 남아있게 되기 때문에, 예외가 발생되더라도 자원을 닫을 수 있도록 아래코드처럼 관례적으로는 try-finally 문을 사용해서 close 처리를 해주곤 했다.

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
try {
    return br.readLine();
} finally {
    br.close();
}

 

이렇게 코드를 작성해주면 IOException이 발생하게 되어도 finally 에서 close를 사용해 자원 사용을 종료하게 된다.
그런데 문제는 다음부터이다.

 

그런데 만약, 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();
    }
}

 

위처럼 코드가 너무 지저분해지는 문제가 생긴다.
게다가 out.close()에서 예외가 발생하면 in.close()가 호출되지 않을 수 있고, 이는 메모리 누수를 발생시킬 수 있다.
그렇기 때문에 java 7 이상에서 사용할 수 있는 try-with-resources 를 사용해야 한다.

 

try-with-resource 가 뭔데?

try-with-resources 구문은 try 블록이 끝난 후 자동으로 close() 메서드를 호출해주는 구문이다

 

그래서 어떻게 사용하는데?

이 구조를 사용하려면 해당 자원이 AutoCloseable 인터페이스를 구현해야 한다.

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class FileCopyExample {
    private static final int BUFFER_SIZE = 1024;

    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);
            }
        }
    }

    public static void main(String[] args) {
        try {
            copy("source.txt", "destination.txt");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

위 코드는 try-with-resources 구문을 사용하고 있다.

 

FileInputStream과 FileOutputStream은 모두 AutoCloseable 인터페이스를 구현하고 있기 때문에 try-with-resources 구문에서 사용할 수 있다.

 

이렇게 작성하는 것이 짧고 읽기 수월하기도 하고 문제를 진단하기에도 훨씬 좋다.


만약 위의 예시에서 readLine과 close에서 예외가 발생한다고 하면

  • close 에서 발생한 예외는 숨겨지고 readLine 에서 발생한 예외가 기록된다.
    • 이처럼 실전에서는 프로그래머에게 보여줄 예외 하나만 보존되고 여러 개의 다른 예외가 숨겨질수도 있다.
    • 숨겨진 예외들은 버려지지않고 스택 추적 내역에 숨겨졌다(suppressed)는 꼬리표를 달고 출력된다.

또한 try-with-resources 에서도 catch 절을 쓸 수 있기 때문에 try문을 더 중첩하지 않고도 다수의 예외를 처리할 수 있다.


아래 코드를 보자

static String firstLineOfFile(String path, String defaultVal) {
    try (BufferedReader br = new BufferedReader(
            new FileReader(path))) {
        return br.readLine();
    } catch (IOException e) {
        return defaultVal;
    }
}

 

이렇게 작성하면 코드도 깔끔해지고 사용도 안전하게 할 수 있으니 유용한 try-with-resources 구문을 모두 잘 사용해보자!

'Java' 카테고리의 다른 글

만두의 Exception?  (0) 2024.08.05
븟츠의 JWT 소개 및 정리  (0) 2024.08.03
만두의 불변객체(Immutable Object)와 record  (0) 2024.07.27
[디자인 패턴] 븟츠의 객체 생성시 생성자 vs 빌더 어떤 것을 사용할까?  (0) 2024.07.20
[디자인 패턴] 만두의 팩토리 메서드 패턴(Factory Method)  (0) 2024.07.14
  1. 들어가며
  2. 그냥 단순히 close를 해주면 문제가 생길 수 있다!
  3. 그런데 만약, close를 여러번 호출해야 하는 상황이 온다면..?
  4. try-with-resource 가 뭔데?
  5. 그래서 어떻게 사용하는데?
'Java' 카테고리의 다른 글
  • 만두의 Exception?
  • 븟츠의 JWT 소개 및 정리
  • 만두의 불변객체(Immutable Object)와 record
  • [디자인 패턴] 븟츠의 객체 생성시 생성자 vs 빌더 어떤 것을 사용할까?
월월월월2
월월월월2
백엔드로 살아남기 입니다.
월월월월2
백엔드로 살아남기
월월월월2
전체
오늘
어제
  • 분류 전체보기 (64)
    • Spring (15)
    • TroubleShooting (2)
    • Infra (7)
    • Java (9)
    • Docker (7)
    • Database (1)
    • Algorithm (9)
    • React (8)
    • CS (2)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

링크

공지사항

인기 글

태그

countingsort
springboot
Docker Out of Docker
낙관적 락
dind
다중 usersdetail
YAML
Spring Security
비관적 락
도커
점층적생성자패턴
스프링스케줄러
트러블슈팅
자바빈즈패턴
사가 패턴
#security
application.properties
react testing library
spring
Java
자바
스프링
MSA
DevOps
Docker in Docker
23288
JPA
Algorithm
연관 관계
Docker

최근 댓글

최근 글

hELLO· Designed By정상우.v4.6.1
월월월월2
븟츠의 try-finally 보다는 try-with-resources를 사용하자!

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.