电商企业网站建设,东莞网站制作公司怎么选择,简单的网站开发模板,个人证书查询网入口免费功能编程允许使用通用语言进行准声明性编程 。 通过使用功能强大的流畅API#xff08;例如Java 8的Stream API #xff09;或jOOλ的顺序Stream扩展Seq或更复杂的库#xff08;例如javaslang或functionaljava#xff09; #xff0c;我们可以以一种非常简洁的方式来表示数… 功能编程允许使用通用语言进行准声明性编程 。 通过使用功能强大的流畅API例如Java 8的Stream API 或jOOλ的顺序Stream扩展Seq或更复杂的库例如javaslang或functionaljava 我们可以以一种非常简洁的方式来表示数据转换算法。 比较相同算法的Mario Fusco的命令式和功能式版本 势在必行–功能分离pic.twitter.com/G2cC6iBkDJ — Mario Fuscomariofusco 2015年3月1日 使用此类API函数式编程肯定感觉就像是真正的声明式编程。 最流行的真正的声明式编程语言是SQL。 当联接两个表时您不会告诉RDBMS如何实现该联接。 它可以自行决定在完整查询和所有可用元信息的上下文中嵌套循环合并联接哈希联接或某种其他算法是否最合适。 这非常强大因为对简单连接有效的性能假设可能对复杂的连接不再有效在复杂的连接上其他算法的性能要优于原始算法。 通过这种抽象您可以轻松地在30秒内修改查询而不必担心诸如算法或性能之类的底层细节。 当一个API允许您将两者结合起来例如jOOQ和Streams 时您将获得两全其美的体验而这些世界并没有太大的不同。 在以下各节中我们将比较常见的SQL构造与使用Streams和jOOλ用Java 8编写的等效表达式以防Stream API无法提供足够的功能 。 元组 为了本文的方便我们将假定SQL行/记录在Java中具有等效的表示形式。 为此我们将使用jOOλ的Tuple类型 该类型实质上是 public class Tuple2T1, T2 {public final T1 v1;public final T2 v2;public Tuple2(T1 v1, T2 v2) {this.v1 v1;this.v2 v2;}
} …加上很多有用的mm头例如“ Comparable Tuple等。 请注意在此示例和所有后续示例中我们假定以下导入。 import static org.jooq.lambda.Seq.*;
import static org.jooq.lambda.tuple.Tuple.*;import java.util.*;
import java.util.function.*;
import java.util.stream.*;import org.jooq.lambda.*; 与SQL行很像元组是“基于值”的类型 这意味着它实际上没有标识。 两个元组(1, A)和(1, A)可以被视为完全等效。 从游戏中删除身份使具有不变数据结构的SQL和函数式编程极为优雅。 FROM ofstream等 在SQL中 FROM子句在逻辑上但不是在语法上位于所有其他子句之前。 它用于从至少一个表可能是多个连接的表生成一组元组。 例如单表FROM子句可以简单地映射到Stream.of() 或简单地生成流的任何其他方法 的SQL SELECT *
FROM (VALUES(1, 1),(2, 2)
) t(v1, v2) 屈服 --------
| v1 | v2 |
--------
| 1 | 1 |
| 2 | 2 |
-------- Java Stream.of(tuple(1, 1),tuple(2, 2)
).forEach(System.out::println); 屈服 (1, 1)
(2, 2)交叉联接 flatMap 从多个表中进行选择已经更加有趣。 在SQL中合并两个表的最简单方法是通过表列表或使用CROSS JOIN生成笛卡尔积。 以下两个是等效的SQL语句 的SQL -- Table list syntax
SELECT *
FROM (VALUES( 1 ), ( 2 )) t1(v1), (VALUES(A), (B)) t2(v2)-- CROSS JOIN syntax
SELECT *
FROM (VALUES( 1 ), ( 2 )) t1(v1)
CROSS JOIN (VALUES(A), (B)) t2(v2) 屈服 --------
| v1 | v2 |
--------
| 1 | A |
| 1 | B |
| 2 | A |
| 2 | B |
-------- 在交叉连接或笛卡尔乘积中将t1中的每个值与t2每个值组合在一起总共产生size(t1) * size(t2)行。 Java 在使用Java 8的Stream函数式编程中 Stream.flatMap()方法对应于SQL CROSS JOIN如以下示例所示 ListInteger s1 Stream.of(1, 2);
SupplierStreamString s2 ()-Stream.of(A, B);s1.flatMap(v1 - s2.get().map(v2 - tuple(v1, v2))).forEach(System.out::println); 屈服 (1, A)
(1, B)
(2, A)
(2, B) 请注意我们必须将第二个流包装在Supplier因为流只能被使用一次 但是上述算法实际上实现了嵌套循环将流s2所有元素与流s1每个元素组合在一起。 另一种选择是不使用流而是使用列表为简单起见我们将在随后的示例中进行此操作 ListInteger s1 Arrays.asList(1, 2);
ListString s2 Arrays.asList(A, B);s1.stream().flatMap(v1 - s2.stream().map(v2 - tuple(v1, v2))).forEach(System.out::println); 实际上 CROSS JOIN可以在SQL和Java中轻松链接 的SQL -- Table list syntax
SELECT *
FROM (VALUES( 1 ), ( 2 )) t1(v1), (VALUES(A), (B)) t2(v2), (VALUES(X), (Y)) t3(v3)-- CROSS JOIN syntax
SELECT *
FROM (VALUES( 1 ), ( 2 )) t1(v1)
CROSS JOIN (VALUES(A), (B)) t2(v2)
CROSS JOIN (VALUES(X), (Y)) t3(v3) 屈服 ------------
| v1 | v2 | v3 |
------------
| 1 | A | X |
| 1 | A | Y |
| 1 | B | X |
| 1 | B | Y |
| 2 | A | X |
| 2 | A | Y |
| 2 | B | X |
| 2 | B | Y |
------------ Java ListInteger s1 Arrays.asList(1, 2);
ListString s2 Arrays.asList(A, B);
ListString s3 Arrays.asList(X, Y);s1.stream().flatMap(v1 - s2.stream().map(v2 - tuple(v1, v2))).flatMap(v12- s3.stream().map(v3 - tuple(v12.v1, v12.v2, v3))).forEach(System.out::println); 屈服 (1, A, X)
(1, A, Y)
(1, B, X)
(1, B, Y)
(2, A, X)
(2, A, Y)
(2, B, X)
(2, B, Y) 请注意我们如何从第一个CROSS JOIN操作中显式取消嵌套元组以在第二个操作中形成“扁平”元组。 当然这是可选的。 Java与jOOλ的crossJoin 我们jOOQ开发人员我们是一个非常注重SQL的人员因此为上述用例添加一个crossJoin()便捷方法是很自然的。 因此我们的三重交叉联接可以这样写 SeqInteger s1 Seq.of(1, 2);
SeqString s2 Seq.of(A, B);
SeqString s3 Seq.of(X, Y);s1.crossJoin(s2).crossJoin(s3).forEach(System.out::println); 屈服 ((1, A), X)
((1, A), Y)
((1, B), X)
((1, B), Y)
((2, A), X)
((2, A), Y)
((2, B), X)
((2, B), Y) 在这种情况下我们并没有嵌套第一个交叉联接中产生的元组。 仅从关系的角度来看这都不重要。 嵌套元组与平面元组相同。 在SQL中我们只是看不到嵌套。 当然我们仍然可以通过添加一个附加的映射来嵌套 SeqInteger s1 Seq.of(1, 2);
SeqString s2 Seq.of(A, B);
SeqString s3 Seq.of(X, Y);s1.crossJoin(s2).crossJoin(s3).map(t - tuple(t.v1.v1, t.v1.v2, t.v2)).forEach(System.out::println); 再次屈服 (1, A, X)
(1, A, Y)
(1, B, X)
(1, B, Y)
(2, A, X)
(2, A, Y)
(2, B, X)
(2, B, Y) 您可能已经注意到map()对应于SELECT 我们稍后将再次看到 内部联接 flatMap与filter SQL INNER JOIN本质上只是SQL CROSS JOIN语法糖其谓词可减少CROSS JOIN后的元组集。 在SQL中以下两种内部联接方式是等效的 的SQL -- Table list syntax
SELECT *
FROM (VALUES(1), (2)) t1(v1), (VALUES(1), (3)) t2(v2)
WHERE t1.v1 t2.v2-- INNER JOIN syntax
SELECT *
FROM (VALUES(1), (2)) t1(v1)
INNER JOIN (VALUES(1), (3)) t2(v2)
ON t1.v1 t2.v2 屈服 --------
| v1 | v2 |
--------
| 1 | 1 |
-------- 请注意关键字INNER是可选的。 因此“ t1的值2和“ t2 ”中的值3被“扔掉”因为它们会产生连接谓词为true的任何行。 可以很容易地表达相同的内容但在Java中则更详细 Java低效率的解决方案 ListInteger s1 Arrays.asList(1, 2);
ListInteger s2 Arrays.asList(1, 3);s1.stream().flatMap(v1 - s2.stream().map(v2 - tuple(v1, v2))).filter(t - Objects.equals(t.v1, t.v2)).forEach(System.out::println); 以上正确产生 (1, 1) 但是要注意在生产笛卡尔积之后您将获得此结果这是每个DBA的噩梦 如本文开头所述与声明式编程不同在函数式编程中您指示程序严格执行指定的操作顺序。 换一种说法 在函数式编程中 您可以定义查询的确切“执行计划” 。 在声明式编程中 优化器可能会重组您的“程序” 没有优化器可以将上述方法转换为效率更高的方法 Java效率更高 ListInteger s1 Arrays.asList(1, 2);
ListInteger s2 Arrays.asList(1, 3);s1.stream().flatMap(v1 - s2.stream().filter(v2 - Objects.equals(v1, v2)).map(v2 - tuple(v1, v2))).forEach(System.out::println); 以上还产生 (1, 1) 注意连接谓词如何从“外部”流转移到“内部”流这是通过传递给flatMap()的函数产生的。 Java最佳 如前所述函数式编程不一定允许您根据对实际数据的了解来重写算法。 上面介绍的用于联接的实现始终实现从第一个流到第二个流的嵌套循环联接。 如果您加入两个以上的流或者第二个流非常大则此方法效率极低。 复杂的RDBMS绝不会像这样盲目地应用嵌套循环联接而要在实际数据上考虑约束索引和直方图。 但是深入探讨该主题将超出本文的范围。 Java与jOOλ的innerJoin 同样受jOOQ工作的启发我们还为上述用例添加了innerJoin()便捷方法 SeqInteger s1 Seq.of(1, 2);
SeqInteger s2 Seq.of(1, 3);s1.innerJoin(s2, (t, u) - Objects.equals(t, u)).forEach(System.out::println); 屈服 (1, 1) …因为毕竟当连接两个流时唯一真正有趣的操作是join Predicate 。 所有其他内容平面映射等都只是样板。 LEFT OUTER JOIN flatMap带有filter和“ default” SQL的OUTER JOIN就像INNER JOIN 除了在JOIN谓词对成对的元组产生false情况下会生成其他“默认”行。 就集合论/关系代数而言 可以表示为 或使用SQL风格的方言 R LEFT OUTER JOIN S ::R INNER JOIN S
UNION ((R EXCEPT (SELECT R.* FROM R INNER JOIN S))CROSS JOIN(null, null, ..., null)
) 这只是意味着左外侧接合时S到R会有在结果至少一行中的每一行R与可能的空值S 。 相反地当右外接合 S到R会有在结果中的每一行的至少一行S 与可能的空值R 最后当完全外部接合 S到R会有在结果中的每一行的至少一行R与可能为空值S 和用于在每行S具有用于可能为空值R 让我们看一下LEFT OUTER JOIN 它是SQL中最常用的。 的SQL -- Table list, Oracle syntax (dont use this!)
SELECT *
FROM (SELECT 1 v1 FROM DUALUNION ALL SELECT 2 v1 FROM DUAL) t1, (SELECT 1 v2 FROM DUALUNION ALLSELECT 3 v2 FROM DUAL) t2
WHERE t1.v1 t2.v2 ()-- OUTER JOIN syntax
SELECT *
FROM (VALUES(1), (2)) t1(v1)
LEFT OUTER JOIN (VALUES(1), (3)) t2(v2)
ON t1.v1 t2.v2 屈服 ----------
| v1 | v2 |
----------
| 1 | 1 |
| 2 | null |
---------- 请注意关键字OUTER是可选的。 Java 不幸的是如果流为空JDK的Stream API不能为我们提供一种从流中产生“至少”一个值的简单方法。 我们可能正在编写实用程序函数如Stack Overflow上的Stuart Marks所述 static T StreamT defaultIfEmpty(StreamT stream, SupplierT supplier) {IteratorT iterator stream.iterator();if (iterator.hasNext()) {return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false);} else {return Stream.of(supplier.get());}
} 或者我们只使用jOOλ的Seq.onEmpty() ListInteger s1 Arrays.asList(1, 2);
ListInteger s2 Arrays.asList(1, 3);seq(s1)
.flatMap(v1 - seq(s2).filter(v2 - Objects.equals(v1, v2)).onEmpty(null).map(v2 - tuple(v1, v2)))
.forEach(System.out::println); 注意我们在流中添加null 。这可能并不总是一个好主意。我们将在以后的博客文章中对此进行跟进 以上还产生 (1, 1)
(2, null) 如何读取隐式左外部联接 我们将从左侧流s1获取每个值v1 对于每个这样的值v1 我们将右流s2平面化以生成元组(v1, v2) 笛卡尔乘积交叉联接 我们将对每个这样的元组(v1, v2)应用连接谓词 如果连接谓词对任何值v2不留下任何元组我们将生成一个包含左流v1的值和null的单个元组 带有jOOλ的Java 为了方便起见jOOλ还支持leftOuterJoin() 其工作原理如上所述 SeqInteger s1 Seq.of(1, 2);
SeqInteger s2 Seq.of(1, 3);s1.leftOuterJoin(s2, (t, u) - Objects.equals(t, u)).forEach(System.out::println); 屈服 (1, 1)
(2, null)右外连接左外连接反向 通常 RIGHT OUTER JOIN只是前一个LEFT OUTER JOIN的逆。 rightOuterJoin()的jOOλ实现如下所示 default U SeqTuple2T, U rightOuterJoin(StreamU other, BiPredicateT, U predicate) {return seq(other).leftOuterJoin(this, (u, t) - predicate.test(t, u)).map(t - tuple(t.v2, t.v1));
} 如您所见 RIGHT OUTER JOIN反转了LEFT OUTER JOIN的结果就是这样。 例如 SeqInteger s1 Seq.of(1, 2);
SeqInteger s2 Seq.of(1, 3);s1.rightOuterJoin(s2, (t, u) - Objects.equals(t, u)).forEach(System.out::println); 屈服 (1, 1)
(null, 3)在哪里 filter 最简单的映射可能是SQL的WHERE子句在Stream API中具有完全等效的内容 Stream.filter() 。 的SQL SELECT *
FROM (VALUES(1), (2), (3)) t(v)
WHERE v % 2 0 屈服 ---
| v |
---
| 2 |
--- Java StreamInteger s Stream.of(1, 2, 3);s.filter(v - v % 2 0).forEach(System.out::println); 屈服 2 通常使用filter()和Stream API的有趣之处在于该操作可以在调用链中的任何位置应用这与WHERE子句不同 WHERE子句被限制为仅放在FROM子句之后-即使SQL的JOIN .. ON或HAVING子句在语义上相似。 GROUP BY collect 最不直接的映射是GROUP BY与Stream.collect() 。 首先 要完全理解 SQL的GROUP BY可能有些棘手 。 它实际上是FROM子句的一部分它将FROM .. JOIN .. WHERE产生的元组集转换为元组组其中每个组都有一个关联的可聚合元组集可以在HAVING SELECT和ORDER BY子句。 当您使用诸如GROUPING SETS类的OLAP功能时事情变得更加有趣它可以根据几种分组组合来复制元组。 在大多数不支持ARRAY或MULTISET SQL实现中可聚合元组在SELECT中不可用即嵌套集合。 在这里 Stream API的功能集非常出色。 另一方面 Stream API只能将值作为终端操作进行分组其中在SQL中 GROUP BY是纯粹以声明方式因此是惰性地应用的。 如果不需要执行计划者可以选择根本不执行GROUP BY 。 例如 SELECT *
FROM some_table
WHERE EXISTS (SELECT x, sum(y)FROM other_tableGROUP BY x
) 上面的查询在语义上等效于 SELECT *
FROM some_table
WHERE EXISTS (SELECT 1FROM other_table
) 子查询中的分组是不必要的。 可能有人从其他地方将子查询复制粘贴到该子查询中或者将查询整体进行了重构。 在Java中使用Stream API总是执行每个操作。 为了简单起见我们将在这里坚持最简单的示例 没有GROUP BY的汇总 一种特殊情况是当我们不指定任何GROUP BY子句时。 在这种情况下我们可以在FROM子句的所有列上指定聚合从而始终只生成一条记录。 例如 的SQL SELECT sum(v)
FROM (VALUES(1), (2), (3)) t(v) 屈服 -----
| sum |
-----
| 6 |
----- Java StreamInteger s Stream.of(1, 2, 3);int sum s.collect(Collectors.summingInt(i - i));
System.out.println(sum); 屈服 6使用GROUP BY进行汇总 在SQL中更常见的聚合情况是指定显式的GROUP BY子句如前所述。 例如我们可能要按偶数和奇数分组 的SQL SELECT v % 2, count(v), sum(v)
FROM (VALUES(1), (2), (3)) t(v)
GROUP BY v % 2 屈服 -------------------
| v % 2 | count | sum |
-------------------
| 0 | 1 | 2 |
| 1 | 2 | 4 |
------------------- Java 幸运的是对于这个简单的分组/收集用例JDK提供了一个称为Collectors.groupingBy()的实用程序方法该方法生成一个收集器该收集器生成MapK, ListV类型如下所示 StreamInteger s Stream.of(1, 2, 3);MapInteger, ListInteger map s.collect(Collectors.groupingBy(v - v % 2)
);System.out.println(map); 屈服 {0[2], 1[1, 3]} 这肯定会照顾到分组。 现在我们要为每个组生成聚合。 有点尴尬的JDK方法是 StreamInteger s Stream.of(1, 2, 3);MapInteger, IntSummaryStatistics map s.collect(Collectors.groupingBy(v - v % 2,Collectors.summarizingInt(i - i))
);System.out.println(map); 我们现在得到 {0IntSummaryStatistics{count1, sum2, min2, average2.000000, max2},1IntSummaryStatistics{count2, sum4, min1, average2.000000, max3}} 如您所见 count()和sum()值是根据上述内容计算出来的。 更复杂的GROUP BY 当使用Java 8的Stream API进行多个聚合时您将很快被迫与自己实现复杂的收集器和累加器的低级API进行角力。 这是乏味且不必要的。 考虑以下SQL语句 的SQL CREATE TABLE t (w INT,x INT,y INT,z INT
);SELECTz, w, MIN(x), MAX(x), AVG(x), MIN(y), MAX(y), AVG(y)
FROM t
GROUP BY z, w; 一口气我们想要 按几个值分组 从多个值汇总 Java 在上一篇文章中我们详细解释了如何使用jOOλ中的便捷API通过 Seq.groupBy() 来实现此目的。 class A {final int w;final int x;final int y;final int z;A(int w, int x, int y, int z) {this.w w;this.x x;this.y y;this.z z;}
}MapTuple2Integer, Integer, Tuple2IntSummaryStatistics, IntSummaryStatisticsmap
Seq.of(new A(1, 1, 1, 1),new A(1, 2, 3, 1),new A(9, 8, 6, 4),new A(9, 9, 7, 4),new A(2, 3, 4, 5),new A(2, 4, 4, 5),new A(2, 5, 5, 5))// Seq.groupBy() is just short for
// Stream.collect(Collectors.groupingBy(...))
.groupBy(a - tuple(a.z, a.w),// ... because once you have tuples, // why not add tuple-collectors?Tuple.collectors(Collectors.summarizingInt(a - a.x),Collectors.summarizingInt(a - a.y))
);System.out.println(map); 以上收益 {(1, 1)(IntSummaryStatistics{count2, sum3, min1, average1.500000, max2},IntSummaryStatistics{count2, sum4, min1, average2.000000, max3}),(4, 9)(IntSummaryStatistics{count2, sum17, min8, average8.500000, max9},IntSummaryStatistics{count2, sum13, min6, average6.500000, max7}),(5, 2)(IntSummaryStatistics{count3, sum12, min3, average4.000000, max5},IntSummaryStatistics{count3, sum13, min4, average4.333333, max5})} 有关更多详细信息 请在此处阅读全文 。 请注意使用Stream.collect()或Seq.groupBy()如何实现隐式SELECT子句不再需要通过map()获得见下文。 再次 filter 如前所述使用Stream API应用谓词并没有真正不同的方法只有Stream.filter() 。 在SQL中 HAVING是一个“特殊”谓词子句在语法上位于GROUP BY子句之后。 例如 的SQL SELECT v % 2, count(v)
FROM (VALUES(1), (2), (3)) t(v)
GROUP BY v % 2
HAVING count(v) 1 屈服 --------------
| v % 2 | count |
--------------
| 1 | 2 |
-------------- Java 不幸的是正如我们之前所看到的 collect()是Stream API中的终端操作这意味着它急切地生成Map 而不是将StreamT转换为StreamK, StreamV 在复杂的Stream组合更好。 这意味着我们要在收集后立即执行的任何操作都必须在从输出Map生成的新流上实施 StreamInteger s Stream.of(1, 2, 3);s.collect(Collectors.groupingBy(v - v % 2,Collectors.summarizingInt(i - i))).entrySet().stream().filter(e - e.getValue().getCount() 1).forEach(System.out::println); 屈服 1IntSummaryStatistics{count2, sum4, min1, average2.000000, max3} 如您所见应用的类型转换为 MapInteger, IntSummaryStatistics SetEntryInteger, IntSummaryStatistics StreamEntryInteger, IntSummaryStatistics SELECT map SQL中的SELECT子句不过是一个元组转换函数该函数采用FROM子句产生的元组的笛卡尔积并将其转换为新的元组表达式然后将其馈送到客户端或某些更高级别的查询如果有这是一个嵌套的SELECT。 插图 从输出 ------------------------------
| T1.A | T1.B | T1.C | T2.A | T2.D |
------------------------------
| 1 | A | a | 1 | X |
| 1 | B | b | 1 | Y |
| 2 | C | c | 2 | X |
| 2 | D | d | 2 | Y |
------------------------------ 应用选择 SELECT t1.a, t1.c, t1.b || t1.d--------------------------
| T1.A | T1.C | T1.B || T1.D |
--------------------------
| 1 | a | AX |
| 1 | b | BY |
| 2 | c | CX |
| 2 | d | DY |
-------------------------- 使用Java 8 Streams可以使用Stream.map()非常简单地实现SELECT 正如我们在前面的示例中已经看到的那样其中我们使用map()取消了元组的嵌套。 以下示例在功能上等效 的SQL SELECT t.v1 * 3, t.v2 5
FROM (VALUES(1, 1),(2, 2)
) t(v1, v2) 屈服 --------
| c1 | c2 |
--------
| 3 | 6 |
| 6 | 7 |
-------- Java Stream.of(tuple(1, 1),tuple(2, 2)
).map(t - tuple(t.v1 * 3, t.v2 5)).forEach(System.out::println); 屈服 (3, 6)
(6, 7)DISTINCT distinct 该DISTINCT可以与被提供的关键字SELECT从句简单地移除它们已经被产生之后立即重复元组SELECT子句。 插图 从输出 ------------------------------
| T1.A | T1.B | T1.C | T2.A | T2.D |
------------------------------
| 1 | A | a | 1 | X |
| 1 | B | b | 1 | Y |
| 2 | C | c | 2 | X |
| 2 | D | d | 2 | Y |
------------------------------ 应用SELECT DISTINCT SELECT DISTINCT t1.a------
| T1.A |
------
| 1 |
| 2 |
------ 使用Java 8 Streams可以在Stream.distinct()之后Stream.map()使用Stream.distinct()来非常简单地实现SELECT DISTINCT 。 以下示例在功能上等效 的SQL SELECT DISTINCT t.v1 * 3, t.v2 5
FROM (VALUES(1, 1),(2, 2),(2, 2)
) t(v1, v2) 屈服 --------
| c1 | c2 |
--------
| 3 | 6 |
| 6 | 7 |
-------- Java Stream.of(tuple(1, 1),tuple(2, 2),tuple(2, 2)
).map(t - tuple(t.v1 * 3, t.v2 5)).distinct().forEach(System.out::println); 屈服 (3, 6)
(6, 7)UNION ALL concat 设置操作在SQL和使用Stream API中都非常强大。 UNION ALL操作映射到Stream.concat() 如下所示 的SQL SELECT *
FROM (VALUES(1), (2)) t(v)
UNION ALL
SELECT *
FROM (VALUES(1), (3)) t(v) 屈服 ---
| v |
---
| 1 |
| 2 |
| 1 |
| 3 |
--- Java StreamInteger s1 Stream.of(1, 2);
StreamInteger s2 Stream.of(1, 3);Stream.concat(s1, s2).forEach(System.out::println); 屈服 1
2
1
3 Java使用jOOλ 不幸的是 concat()仅作为static方法存在于Stream 而使用Seq.concat()时 Seq.concat()也存在于实例上。 SeqInteger s1 Seq.of(1, 2);
SeqInteger s2 Seq.of(1, 3);s1.concat(s2).forEach(System.out::println);UNION concat和distinct 在SQL中定义UNION以在通过UNION ALL将两个集合串联后删除重复项。 以下两个语句是等效的 SELECT * FROM t
UNION
SELECT * FROM u;-- equivalentSELECT DISTINCT *
FROM (SELECT * FROM tUNION ALLSELECT * FROM u
); 让我们付诸行动 的SQL SELECT *
FROM (VALUES(1), (2)) t(v)
UNION
SELECT *
FROM (VALUES(1), (3)) t(v) 屈服 ---
| v |
---
| 1 |
| 2 |
| 3 |
--- Java StreamInteger s1 Stream.of(1, 2);
StreamInteger s2 Stream.of(1, 3);Stream.concat(s1, s2).distinct().forEach(System.out::println);ORDER BY sorted ORDER BY映射很简单 的SQL SELECT *
FROM (VALUES(1), (4), (3)) t(v)
ORDER BY v 屈服 ---
| v |
---
| 1 |
| 3 |
| 4 |
--- Java StreamInteger s Stream.of(1, 4, 3);s.sorted().forEach(System.out::println); 屈服 1
3
4LIMIT limit LIMIT映射更加简单 的SQL SELECT *
FROM (VALUES(1), (4), (3)) t(v)
LIMIT 2 屈服 ---
| v |
---
| 1 |
| 4 |
--- Java StreamInteger s Stream.of(1, 4, 3);s.limit(2).forEach(System.out::println); 屈服 1
4偏移 skip OFFSET映射也很简单 的SQL SELECT *
FROM (VALUES(1), (4), (3)) t(v)
OFFSET 1 屈服 ---
| v |
---
| 4 |
| 3 |
--- Java StreamInteger s Stream.of(1, 4, 3);s.skip(1).forEach(System.out::println); 屈服 4
3结论 在上面的文章中我们已经看到了几乎所有有用的SQL SELECT查询子句以及如何将它们映射到Java 8 Stream API或jOOλ的Seq API以防Stream无法提供足够的功能。 本文表明SQL的声明性世界与Java 8的功能性世界没有太大不同。 SQL子句可以组成即席查询就像Stream方法可以用来组成功能转换管道一样。 但是有根本的区别。 尽管SQL确实是声明性的但是函数式编程仍然很有启发性。 Stream API不会基于约束索引直方图和其他有关正在转换的数据的元信息来做出优化决策。 使用Stream API就像在SQL中使用所有可能的优化提示一样以强制SQL引擎选择一个特定的执行计划而不是另一个。 但是尽管SQL是更高级别的算法抽象但Stream API可能允许您实现更多可自定义的算法。 翻译自: https://www.javacodegeeks.com/2015/08/common-sql-clauses-and-their-equivalents-in-java-8-streams.html