주제 선택 사유

DAO를 생성할 때 반환 타입으로는 어떤 것이 좋을까? 라는 생각에서 선정하게 되었습니다

null이 아닌 빈 컬렉션 또는 배열을 반환하라.

길이가 0인 경우 null을 반환한다면?

빈 컨테이너를 할당하는건 비용이 든다?

👉 빈 컬렉션/배열을 할당하는데 비용이 든다는건 맞는 말이다.

하지만 이 정도 성능 차이는 신경을 써야할 수준은 아니다.빠른 프로그램보다 좋은 프로그램을 만들자

게다가 빈 컬렉션/배열은 새로 할당하지 않아도 반환할 수 있다.

public class Cars {

    private final List<Car> value;

    // AS-IS
    public List<Car> getValueByNull() {
        if (value.isEmpty()) {
            return null;
        }
        return new ArrayList<>(value);
    }

    // TO-BE
    public List<Car> getValue() {
        return new ArrayList<>(value);
    }
}

성능 차이가 궁금해서 getValueByNull와 getValue를 100000번 호출해서 시간을 측정해보았다. 측정할 때마다 다른 결과를 보인다.

# try 1
getValueByNull: 16
getValue: 15

# try 2
getValueByNull: 15
getValue: 16

# try 3
getValueByNull: 10
getValue: 16

# try 4
getValueByNull: 0
getValue: 0

isEmpty() 메서드로 인한 차이인가 싶어서 무조건 null을 반환하도록 시도해았지만 마찬가지로 결과가 항상 랜덤했다.

빈 불변 컬렉션 반환하고 싶다면?

Collections.emptyListCollections.emptyMap 등을 활용할 수도 있다. 이 메서드를 꼭! 사용 해야한다는 의미는 아니다. 빈 불변 컬렉션 반환에 대해 최적화가 필요한 경우 도입하고 실제로 성능이 개선 되는지도 확인해보아야 한다.

jdbcTemplate은 어떤 값을 반환하고 있을까?

현재 제가 자주 사용하고 있는 NamedParameterJdbcTemplate를 이용해 디버깅 해보았습니다.

public class NamedParameterJdbcTemplate implements NamedParameterJdbcOperations {

    // ...

    @Override
    public <T> List<T> query(String sql, SqlParameterSource paramSource, RowMapper<T> rowMapper)
            throws DataAccessException {

        return getJdbcOperations().query(getPreparedStatementCreator(sql, paramSource), rowMapper);
    }
}
public class RowMapperResultSetExtractor<T> implements ResultSetExtractor<List<T>> {

    // ...

    @Override
    public List<T> extractData(ResultSet rs) throws SQLException {
        List<T> results = (this.rowsExpected > 0 ? new ArrayList<>(this.rowsExpected) : new ArrayList<>());
        int rowNum = 0;
        while (rs.next()) {
            results.add(this.rowMapper.mapRow(rs, rowNum++));
        }
        return results;
    }
}