上一节简单讲了lambda的语法,以及lambda代码的简单改造:
这一节是从五个方面详解lambda
一、当遇到函数式接口时使用lambda
定义:
对于只有一个抽象方法的接口,称为函数式接口。比如ActionListener接口,只有actionPerformed一个函数:
public interface ActionListener extends EventListener {
public void actionPerformed(ActionEvent e);
}
当需要调用这种接口的对象时,就可以提供一个lambda表达式(带有参数列表和函数体的函数),来代替原来的接口对象。
举例1
上一节在说回调的时候的打印计时器的例子,是先定义了一个继承了ActionListener的动作类,然后将动作类的对象listener传入计时器Timer类中:Timer timer = new Timer(1000,listener);
由于接口ActionListener只有一个方法,所以可以利用lambda表达式替换的接口唯一的方法:actionPerformed函数,代替接口对象:
Timer timer = new Timer(1000,event->{
//定时1.打印当前时间
System.out.println("准点报时,此时的时间为:"+ Instant.ofEpochMilli(event.getWhen()));
//定时2.响铃
Toolkit.getDefaultToolkit().beep();//getDefaultToolkit获得默认的工具箱,beep发生一声铃响
});
举例2
比如优先级队列的比较器的重写,上一节是这么写的:
PriorityQueue<Integer> que = new PriorityQueue<Integer>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2-o1;
}
}
// (Integer o1,Integer o2)->o2-o1
);
Comparator是只有一个方法的接口,所以在优先队列的需要传入比较器的对象的时候,就可以用lambda表达式代替该接口的对象
PriorityQueue<Integer> que = new PriorityQueue<Integer>(
(Integer o1,Integer o2)->o2-o1
);
2.利用方法引用生成函数式接口的实例
除了利用lambda重写接口的唯一的函数之外还有没有更简洁的方式呢?
比如每隔一秒就执行打印ActionListener对象的操作,用普通的lambda表达式重写是这样的:
Timer timer = new Timer(1000,event->System.out.println(event))
但是用方法引用可以直接使编译器生成一个函数式接口的实例,覆盖这个接口的抽象方法来调用给定方法:
Timer timer = new Timer(1000,System.out::println)
在这里,"::"右边的println和左边的System.out是什么关系呢?
由常用的System.out.printn()可知,System.out一定是一个包含有println()方法的对象,这样才能调用println方法,而这个方法引用使用的就是Object::instanceMethod模式,除此之外,还有
Class::instanceMethod:(Class a,Class b)->a.instanceMethod(b)
Class::staticMethod
共三种方法引用的模式。
第二种模式的使用方法会根据调用函数的参数个数做出调整:
Class::instanceMethod
相当于:
(Class a)->a.instanceMethod();
(Class a,Class b)->a.instanceMethod(b)
举例:
String::trim 等价于x->x.trim()
String:concat等价于(x,y)->x.cancat(y)