您可以为ResultSet创建一个包装器,使其成为Iterable.从那里你可以迭代,也可以创建一个流.当然,您必须定义一个映射器函数以从结果集中获取迭代值.
ResultSetIterable可能如下所示
public class ResultSetIterable implements Iterable {
private final ResultSet rs;
private final Function onNext;
public ResultSetIterable(ResultSet rs, CheckedFunction 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 iterator() {
try {
return new Iterator() {
//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 stream() {
return StreamSupport.stream(this.spliterator(), false);
}
}
现在我们有了包装器,您可以对结果进行流式处理:
ResultSet rs = stmt.executeQuery();
List userIdList = new ResultSetIterable(rs, rs -> rs.getString(1)).stream()
.collect(Collectors.toList())
}
编辑
正如Lukas指出的那样,rs.getString(1)可能抛出一个已检查的SQLException,因此我们需要使用CheckedFunction而不是java函数,它能够在未经检查的情况下包装任何已检查的Exception.
一个非常简单的实现可能是
public interface CheckedFunction extends Function {
@Override
default R apply(T t) {
try {
return applyAndThrow(t);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
R applyAndThrow(T t) throws Exception;
}
或者,您可以使用具有此类功能的库,即jooλ或vavr