越来越多的人通过为他们的业务采用功能性编程来赶上我们平台的最新更新。
在Data Geekery ,我们将Java 8用于jOOQ集成测试,因为将新的Streams API与lambda表达式一起使用使生成临时测试数据变得非常容易。
但是, 我们并不认为JDK提供了尽可能多的功能 ,这就是为什么我们还实现并开源了jOOλ的原因 , jOOλ是一个弥补这些缺点的小型实用程序库。
注意,我们的目的不是要替换更复杂的库,例如Functionaljava 。 jOOλ实际上只是在弥补缺点。
将lambda与jOOλ或jOOQ一起使用
我最近遇到了这个Stack Overflow问题 ,该问题要求将所有列的结果集流式传输到单个列表中。 例如:
输入项
+----+------------+------------+
| ID | FIRST_NAME | LAST_NAME |
+----+------------+------------+
| 1 | Joslyn | Vanderford |
| 2 | Rudolf | Hux |
+----+------------+------------+
输出量
1
Joslyn
Vanderford
2
Rudolf
Hux
这是使用函数式编程而非迭代解决方案的典型教科书示例:
迭代解
ResultSet rs = ...;
ResultSetMetaData meta = rs.getMetaData();List<Object> list = new ArrayList<>();while (rs.next()) {for (int i = 0; i < meta.getColumnCount(); i++) {list.add(rs.getObject(i + 1));}
}
事实是,迭代的解决方案是不是所有的坏,但让我们学会如何这可能是与函数式编程来完成。
使用jOOλ
由于以下几个原因,我们在本示例中使用jOOλ:
- JDBC并没有真正采用新功能。 即使有,也没有简单的
ResultSet
到Stream
转换。 - 不幸的是,新的功能接口不允许抛出已检查的异常。 在Lambda内
try .. catch
块看起来并不好看 - 有趣的是,如果不实现
Iterator
或Spliterator
Iterator
,就无法生成有限的流
因此,这是简单的代码:
ResultSet rs = ...;
ResultSetMetaData meta = rs.getMetaData();List<Object> list =
Seq.generate().limitWhile(Unchecked.predicate(v -> rs.next())).flatMap(Unchecked.function(v -> IntStream.range(0, meta.getColumnCount()).mapToObj(Unchecked.intFunction(i ->rs.getObject(i + 1))))).toList()
到目前为止,这看起来比迭代解决方案冗长(或更多)。 如您所见,这里需要几个jOOλ扩展:
// This generate is a shortcut to generate an
// infinite stream with unspecified content
Seq.generate()// This predicate-based stream termination
// unfortunately doesn't exist in the JDK
// Besides, the checked exception is wrapped in a
// RuntimeException by calling Unchecked.wrapper(...).limitWhile(Unchecked.predicate(v -> rs.next()))// Standard JDK flatmapping, producing a "nested"
// stream of column values for the "outer" stream
// of database rows.flatMap(Unchecked.function(v -> IntStream.range(0, meta.getColumnCount()).mapToObj(Unchecked.intFunction(i ->rs.getObject(i + 1)))))// This is another convenience method that is more
// verbose to write with standard JDK code.toList()
使用jOOQ
jOOQ拥有更多便利API,可用于处理SQL语句的结果记录。 考虑以下逻辑:
ResultSet rs = ...;List<Object> list =
DSL.using(connection).fetch(rs).stream().flatMap(r -> Arrays.stream(r.intoArray())).collect(Collectors.toList());
请注意,上面的示例使用的是标准JDK API,为了方便起见,没有使用jOOλ。 如果您想将jOOλ与jOOQ一起使用,您甚至可以编写:
ResultSet rs = ...;List<Object> list =
Seq.seq(DSL.using(connection).fetch(rs)).flatMap(r -> Arrays.stream(r.intoArray())).toList();
简单? 我会这样说! 让我们记住这个例子:
- 将JDBC ResultSet提取到Java集合中
- 将结果集中的每个记录转换为列值数组
- 将每个数组转换为流
- 将流平整为流
- 将所有值收集到一个列表中
ew!
结论
我们正在走向激动人心的时代! 直到所有Java 8习惯用法和功能思想对于企业中的Java开发人员来说都是“自然”的过程,这将需要一段时间。
但是,拥有一种可以配置为表示为lambda表达式的流水线数据转换的数据源的想法非常引人注目。 jOOQ是一种API,它以非常流畅和直观的方式封装了SQL数据源 ,但并不仅限于此。 jOOQ产生常规的JDK记录集合,可以通过新的stream API对其进行即用转换。
我们认为,这将彻底改变Java生态系统对数据转换的思考方式 。 请继续关注此博客上的更多示例 !
翻译自: https://www.javacodegeeks.com/2014/10/dont-miss-out-on-writing-java-8-sql-one-liners-with-jooλ-or-jooq.html