Java Streams迭代ResultSet对象

Gny*_*nyG 5 resultset java-8 java-stream

我有以下代码片段

ResultSet rs = stmt.executeQuery(); 
List<String> userIdList = new ArrayList<String>(); 
while(rs.next()){
    userIdList.add(rs.getString(1));
}
Run Code Online (Sandbox Code Playgroud)

我可以使用Java流/ Lambda表达式来执行此迭代而不是使用while循环来填充List吗?

Ger*_*cke 9

您可以创建一个包装器来ResultSet制作它Iterable.从那里你可以迭代,也可以创建一个流.当然,您必须定义一个映射器函数以从结果集中获取迭代值.

ResultSetIterable会是这样的

public class ResultSetIterable<T> implements Iterable<T> {

  private final ResultSet rs;
  private final Function<ResultSet, T> onNext;

  public ResultSetIterable(ResultSet rs, CheckedFunction<ResultSet, T> onNext){
    this.rs = rs;
    //onNext is the mapper function to get the values from the resultSet
    this.onNext = onNext;
  }

  private boolean resultSetHasNext(){
     try {
       hasNext = rs.next();
     } catch (SQLException e) {
       //you should add proper exception handling here
       throw new RuntimeException(e);
     }
  }


  @Override
  public Iterator<T> iterator() {

    try {
        return new Iterator<T>() {

            //the iterator state is initialized by calling next() to 
            //know whether there are elements to iterate
            boolean hasNext = resultSetHasNext();


            @Override
            public boolean hasNext() {
                return hasNext;
            }

            @Override
            public T next() {

                T result = onNext.apply(rs);
                //after each get, we need to update the hasNext info
                hasNext = resultSetHasNext();
                return result;
            }
        };
    } catch (Exception e) {
        //you should add proper exception handling here
        throw new RuntimeException(e);
    }
  }

  //adding stream support based on an iteratable is easy
  public Stream<T> stream() {
    return StreamSupport.stream(this.spliterator(), false);
  }
}
Run Code Online (Sandbox Code Playgroud)

现在我们有了包装器,您可以对结果进行流式处理:

ResultSet rs = stmt.executeQuery(); 
List<String> userIdList = new ResultSetIterable(rs, rs -> rs.getString(1)).stream()
                                                                          .collect(Collectors.toList())
Run Code Online (Sandbox Code Playgroud)

}

编辑

正如Lukas指出的那样,rs.getString(1)可能会抛出一个被检查的SQLException,因此我们需要使用CheckedFunction一个java而不是一个Function能够在未经检查的情况下包装任何已检查的Exception 的java .一个非常简单的实现可能是

public interface CheckedFunction<T,R> extends Function<T,R> {

  @Override
  default R apply(T t) {

    try {
        return applyAndThrow(t);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
  }

  R applyAndThrow(T t) throws Exception;
}
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用具有此类功能的库,即jooλvavr

  • 或者你可以使用`org.apache.commons.dbutils.ResultSetIterator.iterable(rowSet)` (2认同)