Search code examples
javarefactoring

How do I reduce null checks using Java 8 lambdas?


I've been reading Uncle Bob's Clean Code and have read many articles on the use of Optionals whenever you are faced with returning a null in a Java method. I'm currently refactoring my code and I just don't know how to optimize it with Optionals. Can someone give me some pointers?

public UserLog selectById(String userid) throws DataException {
    List<UserLog> logs = selectUserLogs(SQL_SELECT_BY_ID, userid);

    return logs.isEmpty() ? null : logs.get(0);
}

private List<UserLog> selectUserLogs(String sql, Object... args) throws DataException {
    List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql, args);

    return rows.stream().map(this::toUserLogs)
            .collect(Collectors.toList());
}

private UserLog toUserLogs(Map<String, Object> row) {
    UserLog userLog = new UserLog("Steven Wozniak", 65, "Male");
    return userLog;
}

/**
* Below shows how selectById is being used in another class
*/
...
public void callingMethod() {
    if(starttime != null && FIVE_HOUR <= durationSinceStartTime() && 
            userLogDao.selectById(userid) != null &&
            userLogDao.selectById(userid).getStartTime() != null) {

        log.warn("Logs came in late");
    }
}

I'm having trouble optimizing the selectById method. Since I'm doing a Collector.toList() in the selectUserLogs method, I can be sure that I will ALWAYS get a List back. It could be an empty list, but never a null.

My initial attempt was:

public Optional<UserLog> selectById(String userid) throws DataException {
    List<UserLog> logs = selectUserLogs(SQL_SELECT_BY_ID, userid);
    return Optional.ofNullable(logs.get(0));
    
}

However, I completely have no idea how I'm going to optimize the calling of this method and performing the null checks in the callingMethod(). How would I re-write that so that it looks a tad more elegant?


Solution

  • For your code, I only see this improvement. If you don't get null from selectUserLogs (and I also prefer an empty list than null), yo can update selectById and callingMethod to this:

    public Optional<UserLog> selectById(String userid) throws DataException {
        List<UserLog> logs = selectUserLogs(SQL_SELECT_BY_ID, userid);
    
        return logs.isEmpty() ? Optional.empty() : Optional.of(logs.get(0));
    }
    
    public void callingMethod() {
        if (starttime != null && FIVE_HOUR <= durationSinceStartTime()) {
            userLogDao.selectById(userid)
                    .map(UserLog::getStartTime)
                    .ifPresent(startTime -> log.warn("Logs came in late"));
        }
    }