본문 바로가기

Java

[Java] try-with-resource

리소스란?

리소스는, 프로그램이 끝난 후 닫아야 하는 개체이다.

 

예를 들어, JDBC를 사용하여 데이터베이스에 접근하는 경우를 생각해보자.

 

Connection 객체를 얻고, Statement 객체를 얻고, ResultSet 객체를 얻어 작업을 완료한 후, 해당 개체들을 close()하지 않으면 안되는데, 이런 개체들을 리소스라고 한다.

 

아래의 코드는 JDBC를 사용하여 데이터베이스에서 role 객체를 얻어오는 부분이다.

코드 상의 finally 부분을 보면, 리소스를 닫는 코드를 작성한 것을 볼 수 있다.

package com.example.jdbcpractice.dao;

import com.example.jdbcpractice.dto.Role;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class RoleDao {

    private static String dbUrl = "jdbc:mysql://localhost:3306/connectdb";
    private static String dbUser = "connectuser";
    private static String dbPassword = "connect123!@#";

    // 1. select
    public Role getRole(Integer roleId) {
        Role role = null;
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;

        try {
            Class.forName("com.mysql.cj.jdbc.Driver"); // 1. 드라이버 로딩하기

            conn = DriverManager.getConnection(dbUrl, dbUser, dbPassword); // 2. db에 접속 가능한 connection 객체 얻기
            String sql = "select role_id, description from role where role_id = ?"; // 쿼리 만들기

            ps = conn.prepareStatement(sql); // 3. statement 객체 만들기 (쿼리문 넣어서)
            ps.setInt(1,roleId);

            rs = ps.executeQuery(); // 4. statement 객체 실행시키기 & rs에 결과값 받아오기

            if (rs.next()) {
                String description = rs.getString(1);
                int id = rs.getInt("role_id");
                role = new Role(id, description);
            }


        } catch (Exception e) {
            e.printStackTrace();

        } finally { // 반드시 객체 사용 후 닫아야 하므로, 미리 finally 구문 완성하기
            if (conn != null) {
                try {
                    conn.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if (ps != null) {
                try {
                    ps.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if (rs != null) {
                try {
                    rs.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }


        return role;
    }
}

 

일반적으로 리소스는 try-catch-finally 문을 사용해 반드시 close()를 하도록 코드를 작성하게 된다.

하지만, try-with-resource를 사용하면 finally에서 close()를 하지 않아도, 자동으로 리소스를 닫아준다.

 

try-with-resource

try("~~~") 의 ~~~ 부분에서 사용하기를 원하는 리소스를 생성하도록 코드를 작성하면, try문이 정상적으로 작동했는지, 이상하게 동작했던지 간에, 리소스를 반드시 닫아주는 역할을 한다.

 

위의 예제코드를 try-with-resource로 바꾼 예제는 아래와 같다.

// 1. select
public Role getRole(Integer roleId) {
    Role role = null;
    
    try {
        Class.forName("com.mysql.cj.jdbc.Driver"); // 1. 드라이버 로딩하기
    } catch (Exception e) {
        e.printStackTrace();
    }
    String sql = "select role_id, description from role where role_id = ?"; // 쿼리 만들기

    try (Connection conn = DriverManager.getConnection(dbUrl, dbUser, dbPassword); // 2. connection 객체 얻기
         PreparedStatement ps = conn.prepareStatement(sql)) { // 3. statement 객체 얻기
        ps.setInt(1, roleId);
        
        try (ResultSet rs = ps.executeQuery()) { // 4. statement 객체 실행 & resultSet 객체 얻기
            if (rs.next()) {
                String description = rs.getString(1);
                int id = rs.getInt("role_id");
                role = new Role(id, description);
            }
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    } catch (Exception e) {
        e.printStackTrace();
    }

    return role;
}