Java8特性尝鲜之集合排序
Published:
03 Mar 2014
Category:
Java
只要提到Java8的lambda表达式,数组或者集合的排序都是一个非常棒的例子,这是因为自从Java1.2以来,只要一提到排序,Comparator这个接口总是挥之不去。有了Java8后,在很多排序中,Comparator都可以使用lambda表达式来替换了。
在接下来的例子中,我们会用到这个简单的Person类:
很明显,只要我们让Person类实现Comparable接口就可以让它支持排序了,不过我们现在考虑的是使用外部的Comparator进行排序的情况。来看下下面这个Person列表,其中名字是由某个在线随机名字生成器生成的:
我们希望是先根据姓氏排序,然后根据名字排序。
Java 7中的排序
使用Comparator的一个经典的Java 7的例子是:
上述代码的输出结果是:
Java 8的排序
现在我们来把上面排序的代码改成Java8的风格:
结果当然是一样的。上面的代码是什么意思?首先,我们将一个lambda表达式赋值给一个Person的Comparator的本地变量:
不像Scala,c#或者Ceylon这些语言,他们可以从表达式中进行类型推导,本地变量的声明只需要用一个val关键字(或者类似的)就可以了,而Java是从变量声明到赋值的表达式进行推导的。
简单的话,可以这么说,类型推导是从左到右,而不是从右到左的。这样让Comparator显得有点笨重,因为Java不能当参数传递到sort方法时才做类型推导。
一旦我们把Comparator赋值给一个变量后,我们可以通过thenComparing方法很方便的把别的比较器增加到这个比较链中:
最后,我们把这个Comparator传给列表的新的sort方法,它是List接口里面默认实现的一个方法:
上述局限性的一个解决方法
虽然Java类型推导的这个小缺陷令人有点沮丧,但是我们可以通过创建一个泛型的IdentityComparator来解决这个问题:
使用上面这个compare方法,我们就可以很流畅地完成一个比较器链的编写了:
提取关键字
我们还可以进一步改进。因为我们一般只使用Comparator参数的POJO/DTO对象的同样一个值进行比较,我们用一个"提取关键值"的函数把它们传给这些新的API。下面是示例:
对于一个指定的Person对象,我们给接口提供一个提取的函数,比如,p.lastname。事实上,一旦我们使用了关键值提取器,我们可以省略上面的那个帮助方法,因为库里面也提供了一个comparing的方法来初始化整个调用链:
同样的,由于编译器无法进行类型推导,我们告诉它具体的类型,尽管在这个例子中sort方法已经提供了足够的信息了。想了解更多关于Java8的泛型推导的资料,请看下我们之前发的一些文章。
结论
跟Java5一样,升级最大的提升主要体现在JDK中。Java5给Comparator带来的是类型安全,而Java8则是让我们能更方便的使用它们。
原创文章转载请注明出处:Java8特性尝鲜之集合排序
英文原文链接