函数式接口:
定义:只有一个抽象方法的接口。
与lambda表达式的关系:与lambda表达式是兼容的,当需要函数式接口的对象时,就可以提供个lambda表达式来代替。例如Comparator接口是函数式接口,仅含有compare一个方法。
代码如下:
public interface Comparator<T>//Comparator接口定义
{
int compare(T first,T second);
}
Comparator<String> one=(String first,String second)->first.length()-second.length();
//将lambda表达式的内容赋给函数式表达式Comparator的对象one。
String[] a={.............};
Arrays.sort(a,one);
最好把lambda表达式看成是一个函数,而不是一个对象。
实际上,在Java中,对lambda表达式所能做的也只是转换为函数式接口。
举例几个常用函数式接口
1.BiFunction<T,U,R>描述了参数类型为T和U而且返回类型为R的函数。可以将我们的字符串比较lambda表达式保存在这个类型的变量中:
BiFunction<String,String,Integer>comp=(first,second)->first.length()-second.length();
2.接口Predicate专门用来传递Lambda表达式。下面的语句将从一个数组列表删除所有Null值:
list.removeIf(e->e==null);
方法引用:
有时,lambda表达式涉及一个方法。例如,你希望出现一个定时器事件就打印这个事件对象。可以调用:
var timer=new Timer(1000,event->System.out.println(event));
也可以将println方法直接传递到Timer构造器中。
var timer=new Timer(1000,System.out::println);
表达式System.out::println是一个方法引用,它指示编译器生成一个函数式接口的实例,覆盖这个接口的抽象方法来调用给定的方法。在这个例子中,会生成一个ActionListener,它的actionPerformed(ActionEvent e)方法调用System.out.println(e)。
再看一个例子,如果你想对字符串进行排序,而不考虑字母的大小写。可以传递以下方法表达式:
Arrays.sort(strings:String::compareToIgnoreCase)
从这些例子中可以看出,要用::运算符分隔方法名与对象或类名。主要有以下三种情况:
1.object::instanceMethod
2.Class::instanceMethod
3.Class::staticMethod
第一种情况下等价于向方法传递参数的lambda表达式。对于System.out::println,对象是System.out,等价于x->System.out.println(x)。
第二种情况,第一个参数为方法的隐式参数。例如,String::compareToIgnoreCase等同于(x,y)->x.compreToIgnoreCase(y)。
第三种情况下,所有参数都传递到静态方法:Math::pow等价于(x,y)->Math.pow(x,y)。
其他情况如下:
!!!注意:只有当lambda表达式的体只调用一个方法而不做其他操作时,才能把lambda表达式写为方法引用。
可以在方法引用中使用this参数。例如,this::equals等同于x->this.equals(x)。使用super也是合法的。
class Greeter
{
public void greet(ActionEvent event)
{
System.out.println("Hello,the time is"+Instant.ofEpochMilli(event.getWhen()));
}
}
class RepeatedGreeter extends Greeter
{
public void greet(ActionEvent event)
{
var timer=new Timer(1000,super::greet);//调用Greeter的greet方法。
timer.start();
}
}