首先创建一个函数接口 ResultSetProcessor
:
@FunctionalInterface
public interface ResultSetProcessor {
public void process(ResultSet resultSet, long currentRow) throws SQLException;
}
下面做个简单查询案例,使用这个接口遍历
public static void select(Connection connection, String sql, ResultSetProcessor processor, Object... params) {
try (PreparedStatement ps = connection.prepareStatement(sql)) {
int cnt = 0;
for (Object param : params)
ps.setObject(++cnt, param));
try (ResultSet rs = ps.executeQuery()) {
long rowCnt = 0;
while (rs.next())
processor.process(rs, rowCnt++);
} catch (SQLException e) {
throw new DataAccessException(e);
}
} catch (SQLException e) {
throw new DataAccessException(e);
}
}
调用这个 select 语句如下:
select(connection, "select * from MY_TABLE",(rs, cnt)-> {
System.out.println(rs.getInt(1)+" "+cnt)
});
select 的第三个参数 ResultSetProcessor 这是个函数,所以我们传入的是一个匿名函数。
Streams API
Java 8 提供了更强大的 Streams API,我们可以对 ResultSet 处理更加强大。创建一个自己的 Tuple 类型,代表 ResultSet 中一行记录。下面我们将一个查询和 ResultSet 包装在一个 Iterator 中:
public class ResultSetIterator implements Iterator {
private ResultSet rs;
private PreparedStatement ps;
private Connection connection;
private String sql;
public ResultSetIterator(Connection connection, String sql) {
assert connection != null;
assert sql != null;
this.connection = connection;
this.sql = sql;
}
public void init() {
try {
ps = connection.prepareStatement(sql);
rs = ps.executeQuery();
} catch (SQLException e) {
close();
throw new DataAccessException(e);
}
}
@Override
public boolean hasNext() {
if (ps == null) {
init();
}
try {
boolean hasMore = rs.next();
if (!hasMore) {
close();
}
return hasMore;
} catch (SQLException e) {
close();
throw new DataAccessException(e);
}
}
private void close() {
try {
rs.close();
try {
ps.close();
} catch (SQLException e) {
//nothing we can do here
}
} catch (SQLException e) {
//nothing we can do here
}
}
@Override
public Tuple next() {
try {
return SQL.rowAsTuple(sql, rs);
} catch (DataAccessException e) {
close();
throw e;
}
}
}
这是一个遍历器,每次返回 ResultSet 的一行记录,返回类型是我们定义 Tuple。关于 tuple 定义可见源码。我们和 Stream 绑定在一起如下:
public static Stream stream(final Connection connection, final String sql, final Object... parms) {
return StreamSupport
.stream(Spliterators.spliteratorUnknownSize(
new ResultSetIterator(connection, sql), 0), false);
}
Java 8 提供 StreamSupport 静态方法 .stream 来创建 java.util.stream.Stream
实例,同时还需要 java.util.stream.Spliterator
,这是一个用来遍历和分区一个序列元素(集合)的特殊类型,有了它才能并行处理我们饿操作,而 Spliterators 这是能够对已经存在的集合如 java.util.Iterator
提供并行操作。我们调用上面 stream 如下:
long result = stream(connection, "select TEST_ID from TEST_TABLE")
.filter((t) -> t.asInt("TEST_ID") % 2 == 0)
.limit(100)
.count();
这是查询所有的 TEST_ID,然后过滤掉所有非偶数,最后再运行一个计数。非常简单明了。如果你使用 ORM/JPA 等框架,可能无法让自己的 SQL 代码如此优雅直接了,它类似 Hibernate 的 criteria。
本教程源码下载 https://github.com/jexenberger/lambda-tuples
原文:https://dzone.com/articles/adding-java-8-lambda-goodness