摘要: 如果我们在Java中也提供有一套完整的结构化数据处理和计算类库,那这个问题就能得到解决:即享受到架构的优势,又不致于降低开发效率。
现代Java应用架构越来越强调数据存储和处理分离,以获得更好的可维护性、可扩展性以及可移植性,比如火热的微服务就是一种典型。这种架构通常要求业务逻辑要在Java程序中实现,而不是像传统应用架构中放在数据库中。
应用中的业务逻辑大都会涉及结构化数据处理。数据库(SQL)中对这类任务有较丰富的支持,可以相对简易地实现业务逻辑。但Java却一直缺乏这类基础支持,导致用Java实现业务逻辑非常繁琐低效。结果,虽然架构上有各种优势,但开发效率却反而大幅下降了。
如果我们在Java中也提供有一套完整的结构化数据处理和计算类库,那这个问题就能得到解决:即享受到架构的优势,又不致于降低开发效率。
需要什么样的能力?
Java下理想的结构化数据处理类库应当具备哪些特征呢?我们可以从SQL来总结:
1 集合运算能力
结构化数据经常是批量(以集合形式)出现的,为了方便地计算这类数据,有必要提供足够的集合运算能力。
如果没有集合运算类库,只有数组(相当于集合)这种基础数据类型,我们要对集合成员做个简单地求和也需要写四五行循环语句才能完成,过滤、分组聚合等运算则要写出数百行代码了。
SQL提供有较丰富的集合运算,如 SUM/COUNT 等聚合运算,WHERE 用于过滤、GROUP 用于分组,也支持针对集合的交、并、差等基本运算。这样写出来的代码就会短小很多。
2 Lambda语法
有了集合运算能力是否就够了呢?假如我们为 Java 开发一批的集合运算类库,是否就可以达到 SQL 的效果呢?
没有这么简单!
以过滤运算为例。过滤通常需要一个条件,把满足条件的集合成员保留。在 SQL 中这个条件是以一个表达式形式出现的,比如写 WHERE x>0,就表示保留那些使得 x>0 计算结果为真的成员。这个表达式 x>0 并不是在执行这个语句之前先计算好的,而是在遍历时针对每个集合成员计算的。本质上,这个表达式本质上是一个函数,是一个以当前集合成员为参数的函数。对于 WHERE 运算而言,相当于把一个用表达式定义的函数用作了 WHERE 的参数。
这种写法有一个术语叫做 Lambda 语法,或者叫函数式语言。
如果没有 Lambda 语法,我们就要经常临时定义函数,代码会非常繁琐,还容易发生名字冲突。
SQL中大量使用了 Lambda 语法,不在于必须过滤、分组运算中,在计算列等不必须的场景也可以使用,大大简化了代码。
3 在 Lambda 语法中直接引用字段
结构化数据并非简单的单值,而是带有字段的记录。
我们发现,SQL 的表达式参数中引用记录字段时,大多数情况可以直接使用字段名称而不必指明字段所属的记录,只有在多个同名字段时才需要冠以表名(或别名)以区分。
新版本的 Java 虽然也开始支持 Lambda 语法了,但只能把当前记录作为参数传入这个用 Lambda 语法定义的函数,然后再写计算式时就总要带上这个记录。比如用单价和数量计算金额时,如果用于表示当前成员的参数名为 x,则需要写成“x. 单价 *x. 数量”这种啰嗦的形式。而在 SQL 中可以更为直观地写成 " 单价 * 数量”。
4 动态数据结构
SQL还能很好地支持动态数据结构。
结构化数据计算中,返回值经常也是有结构的数据,而结果数据结构和运算相关,没办法在代码编写之前就先准备好。所以需要支持动态的数据结构能力。</