Java

Lesson 05

try-with-resources cleanup

Use try-with-resources for files, connections, statements, and result sets so cleanup happens on success and failure.

Good Code

src/main/java/dev/review/user/JdbcUserRepository.java
public Optional<User> findByEmail(String email) throws SQLException {
    String sql = "select id, email, name from users where email = ?";

    try (
        Connection connection = dataSource.getConnection();
        PreparedStatement statement = connection.prepareStatement(sql)
    ) {
        statement.setString(1, email);

        try (ResultSet rows = statement.executeQuery()) {
            if (!rows.next()) {
                return Optional.empty();
            }

            return Optional.of(mapUser(rows));
        }
    }
}

Bad Code

src/main/java/JdbcUserRepository.java
public User findByEmail(String email) throws SQLException {
    Connection connection = dataSource.getConnection();
    PreparedStatement statement = connection.prepareStatement(
        "select * from users where email = '" + email + "'"
    );

    ResultSet rows = statement.executeQuery();
    if (!rows.next()) {
        return null;
    }

    connection.close();
    return mapUser(rows);
}

Review Notes

What to review

Good Code

The good version makes resource ownership visible. Connections, statements, and result sets are closed even when the query or mapping throws.

Bad Code

The bad version manually closes only one resource on the happy path, skips cleanup on early returns, and mixes unsafe SQL construction into the same method.

Takeaways

  • Any Java object that must be closed should have an obvious owner and a cleanup path that survives exceptions.