一、问题的提出
实现自定义类对象之间的比较可以使用向Collections.sort或Arrays.sort方法传递一个Comparator函数式接口的方法实现,而实现函数式接口有多种方法,下面将主要阐述使用lambda表达式的实现方法。
依然使用不可变类Interval:
/**
* An interval defind by start and end, start <= end,
* represents the section from start to end including both start and end.
*
* Interval is immutable
*/
public class Interval {
private final long start;
private final long end;
二、概述
查看java API可以了解到FunctionalInterface的基本信息:
根据API的描述,函数式接口是只有一个抽象方法的接口,这使它能够以一种简单的形式实现在lambda表达式里。
实现函数式接口还可以通过方法引用或构造引用。
三、使用lambda表达式实现函数式接口
函数式接口作为一种特殊接口,可以像实现普通接口那样实现它,如为其写一个实现类,或使用内部匿名类:
/**内部匿名类 */
Collections.sort(list, new Comparator<Interval>() {
@Override
public int compare(Interval o1, Interval o2) {
if (o1.getStart() < o2.getStart())
return -1;
else if (o1.getStart() > o2.getStart())
return 1;
else
return 0;
}
});
函数式接口的特殊定义意味着它可以用一种不同的方式实现--在lambda表达式中实现。
第一种:
Collections.sort(list, (Interval o1, Interval o2) -> compareFunc(o1.getStart(), o2.getStart()));
其中compareFunc定义如下:
public static int compareFunc(long l1, long l2) {
if (l1 < l2)
return -1;
else if (l1 > l2)
return 1;
else
return 0;
}
在底层,Collections.sort方法会接收一个实现了Comparator<Interval>的某个类的对象,调用compare方法时会执行这个lambda表达式。
lambda表达式的类型是取决于上下文的,称为“目标类型”,甚至参数的类型也可以从上下文中获取而无需声明。
第二种:
Comparator<Interval> cmp = (o1, o2) -> compareFunc(o1.getStart(), o2.getStart());
Collections.sort(list, cmp);
声明一个函数式接口引用,指向lambda表达式,这里的形参不用声明类型,因为可以从cmp的声明中得知它们是Interval类的。
这也是一种存储lambda表达式的方法。
第三种:
BiFunction<Interval, Interval, Integer> comp = (Interval o1, Interval o2) -> compareFunc(o1.getStart(),
o2.getStart());
使用默认函数式接口BiFunction保存lambda表达式,它的声明表示这是一个需要两个Interva形参、返回值为Integer的方法。
但这种方法不能用来排序,因为Collections或Arrays的sort方法不会接收一个函数式接口作为参数。
四、函数式接口与Object
函数式接口是不同于Object的,即使在底层lambda表达式会作为某个类的对象存在,但其类型终究只是不确定的“目标类型”,这意味着下面的赋值操作是错误的:
Object o = (o1, o2) -> compareFunc(o1.getStart(), o2.getStart());
同样,lambda表达式也不能作为Object参数传递,下面的语句也是错误的:
System.out.println((o1, o2) -> compareFunc(o1.getStart(), o2.getStart()));
这时就需要显式的转换成函数式接口再赋值给Object:
Object o = (Comparator<Interval>) (o1, o2) -> compareFunc(o1.getStart(), o2.getStart());
System.out.println((Comparator<Interval>) (o1, o2) -> compareFunc(o1.getStart(), o2.getStart()));
五、小结
本文简单阐述了用lambda表达式实现函数式接口的方法,lambda表达式的类型是取决于上下文的,不同于Object。