lambda是一个代码段,以及必须传入代码的变量规范。主要用来简化代码。
引入
拿Array.sort(T[],Comparator<? super T>)
方法举例,该方法接收一个泛型数组,以及一个该类型对应的比较器(Comparator接口)。
查看Comparator
接口的代码,其包含compare
的抽象方法,如果需要创建自定义比较规则,则需要自定义一个类实现Comparator接口
,然后实例化对象,并将这个对象传递给sort
方法。
|
|
使用lambda之后,可以将MyComparator
作为代码段直接丢入sort
中:
|
|
lambda语法
lambda使Java支持函数式编程,主要格式为(/*参数列表*/)->{/*函数体*/}
。
如果函数体只有一行代码,可以省略花括号和return
,但是上例在这么做了之后,IDEA提示我可以进一步简化:
简化之后:
Arrays.sort(s, Comparator.comparingInt(String::length));
使用了Comparator
接口的静态方法comparingInt
,看下源码:
|
|
comparingInt
的接受一个ToIntFunction
类型的叫做var0的函数式接口,但是实际给出的是String::length
.String::length
等价于s -> s.length()
等价于s -> { return s.length() }
这样就整明白了,Comparator.comparingInt
表示我要比较的是Int类型,但是给的是String类型,所以还需要一个类型转换器。
我需要比较字符串大小的话,就需要用到String的length,ToIntFunction
就是定义这样的类型转换规则的接口,通过看他的源码可以发现:
|
|
它只有一个接口,把泛型转换为int类型,之后会说到这个是Java的函数式接口。所以这里就相当于我定义了这样的接口:
|
|
和简化的lambda对比Arrays.sort(s, Comparator.comparingInt(String::length));
确实简化了不少。
关于comparingInt
静态方法
再深入一点,上文comparingInt
方法中,拿到的其实还是一个接口引用,只是后来在comparingInt
里面,又通过lambda+调用接口引用(ToIntFunction)的applyAsInt
方法+Integer.compare
具体实现了。
但是这里我有有一个疑问,书里说Java根据lambda表达式所处方法的参数类型自动转换为对应的接口,但是如果lambda出现在普通代码中,如何确定类型?
在JDK源码中,我觉得是通过强制类型转换。
方法引用
一个例子:Arrays.stream(s).forEach(System.out::println);
- object::instanceMethod
- Class::staticMethod
- Class::instanceMethod
前两个类似这样:System.out::println
== x -> System.out.println(x)
第三种情况,第一个参数会成为方法的目标,余下的成为参数列表。this::xxx
super::xxx
是合法的
构造器引用
Class::new
数组类型的构造器引用
int[]::new
等同x -> new int[x]