上一节简单讲了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)