文章目录
- Lambda 语法概览
- Lambda 表达式语法
- 1.Lambda 表达式与函数接口
- 2.Lambda 遇上 this final
Lambda 语法概览
String(] names = {”Justi n ”,”caterpillar”,”Bush " };
Arrays . sort (names, new Compara tor<String> () {
publ int compare (String namel , String name2) {
retu rn namel . length () - name2 . length() ;
}
});
Arrays ort ()方法可以用来 ,只不过,你得告诉它两个元 比较时顺序是什么, sort()
规定得操作 java.util Comparator 说明这件事,然而那个匿名类的语法有些冗长。先别急着
使用 Lambda 法, 如果想稍微改变一下 Arrays sort ()该行的可读性,在 JDK8 出现前,可以
Comparator<String> byLength =new Comparator<String>() {
public int compare(String namel , String name2) {
return namel . length() - name2 . length();
}
});
String[] names = {”Justin”,”caterpillar”,”Bush ” );
Arrays . sort (names, byLength) ;
通过变量 byLength ,确实是可以让排序的意图清楚许多,只是操作 Comparator 时的匿名类
依旧冗长,有太多重复的信息,如果使用 JDK8 的话,可以使用 Lambda 特性去除重复的信息。
例如,声明 byLength 时已经写了一次 Comparator<String >,为什么操作匿名类时又得写一
Comparator<String ?使用 JDK8 Lambda 表达式的话,可以 为:
Comparator byLength =
(String namel , Str ng name2) -> namel . length() - name2 . length( );
重复 Comparator<String >信息从等号右边去除了,因为原 匿名类只有 个方法要操
作,因此在使用 Lambda 达式时,实际上从等号左边的 Corr rator<String >声 明就可以知道,
Lambda 表达式实际上是要操作 Comparator<Str 工口 compare ()方法。仔细看看,还有重复
信息,既然声明变量时使用了 Comparator<String >,为什么 Lambda 表达式的参数上又得声明一
String ?实际上确实不用,因为编译程序可 以从 byLength 变量的声明类型,推断 name1、name2 类型 ,因此可以再简化为:
Cornparator<String> byLength = (narnel , narne2) - > narnel. length() - narne2 . length() ;
直接放 Arrays sort ()方法中
package cc . openhorne ;
import java . util . Arrays;
public class LarnbdaDerno {
public stat VO rnain(String[] args) {
String[] names = {”Justin”,”caterpillar”,”Bush” );
Arrays . sort (names , (namel , name2) -> namel . length() - name2. length() );
Systern . out .println(Arrays.toString(narnes)) ;
}
}
Lambda 表达式语法
1.Lambda 表达式与函数接口
如果接口里只有一个抽象方法,那么就是函数式接口,可以使用注解(@FunctionalInterface)检测该接口是否是函数式接口,即只能有一个抽象方法。
Comparator<St ring> byLength =
(String namel , String name2) - > namel . length( ) - name2.length ();
拆开为两 分, 等号右 Lambda 表达 Expressio ,等号左 作为 Lambda
达式的目标类型 Target Type 。先来看看等号右边的 Lambda 表达式
(String namel , String ame2 - > namel . l e ngth() name2 . length()
Lambda 达式表示接受两 参数 namel name2 ,参数 String 类型,目前-〉右
义了 返回结果 式, 果运算 比较复杂,必须使 多行描述, 以加入门定
述区块,如果 返回值,必须加 return ,例如:
(String namel , String ame2) - > {
Stri ng namel = namel.trim() ;
String name2 = name2.trim() ;
return namel . length () - name2 . length ();
}
区块可 由数个描述语句组成 本上不 议如此使用。在 Lambda 表达式时
尽量使用简单的 ,如 操作比较复杂,可以 方法参考等其 方式。
Lambda 中,即 接受任何 数,也必须 下括号。 例如:
()-> Justi //不接受参数 返回字符串
() -> System.out.println () //不接受参数 没有返回值
只有Lambda 达式的情况下, 参数的类型必须写 ,如果有 目标类型的话,在编译程
序可推断 类型 况下, 就可 以不写出 Lambda 参数类型。 例如以下范例可以
Comparator<String 中推断出 namel name2 的类型, 实际 String ,因而就不用写 参数类型:
Comparator<Str ng> byLength = (namel , name2) -> namel. length() -name2.length () ;
Lambda 式本身是中性的, 表任 类型 ,同样 Lambda 表达式可用来
表示不 同目标类型 的对象操 。举例而 (name1,name2 ) -> namel1. length () - name2 . length ()
的范例中,用来表示 Comparator 的操作:
public interface Func<P,R>{
R apply(P p1, P p2)();
}
同样是(namel , name2) -> namel. length() -name2.length () 这个 达式, 在以下的代码程序中:
Func<String,Integer> func = (name1,name2) -> name1.length() - name2.length();
就是用来表示 目标类型 Func<String Integer 作, 个例 也示范 如何
Lambda 达式的 类型 Lambda 并没有导入新类型来作为 Lambda 达式的类型 ,而
就现 interface 语法来定义函数接口(Funeti onal Interface ),作为 Lambda 达式的目标
接口 就是接 口,但 求仅具单 抽象方 ,许 口都 这种接 ,如
API 中的 Runnable Callable Comparator ,都只 义了 方法。
public interface Runnable {
roid run();
}
public interface Callable<V> {
V call () throws Exception;
}
public interface Comparator<T> {
int compare(T ol , T o2) ;
}
在撰写 Lambda 表达式时,若编译程序可推断出类型,本来可以写为:
Fune func = (s) - > out.println(s) ;
这时括号 是多余 了,可 省略写为:
Fune func = s - > out . println(s) ;
函数接口是仅具单 象方法的接口,不过有时会难 直接分辨接 口是否为函数接口,稍
后就会看到,因为 JDK8 interface 语法做了改进,允许有默认方法 Default Method
而接口可能继承其他接口、 重新定义 某些方法等,这些都会使得确认接口是否为函数接口更为困难。有个新标注 @FunctionalInterface JDK8 被引入,它可以这么使用:
@Functional Interface
public interface Func<P, R> {
R appl y (P p) ;
}
如果接口使用了@Funct inalinterfac 来标注,而本身并非函数接口的话,就会引发编译错
误。例如 以下这个接口:
@Fun ct onalinterface
public interface Function<P, R> {
R call (P p) ;
R call(P pl , P p2);
}
2.Lambda 遇上 this final
Lambda 式并不是匿名类的语法蜜糖,如果将它当作语法蜜糖 this 实际参考对
象时,就会觉得困惑。先来看 下接下来的程序 了匿名类,先想想看结果会如何显示?
package cc.openhome ;
import static java . lang . System.out ;
class Hello {
Runnable rl =new Runnable() {
public void run() {
out.println (this) ;
}
};
Runnable r2 = new Runnable(){
public void run() {
out.println (toString());
}
};
public String toString () {
return "Hello , world";
}
public class ThisDemo {
public static void main(String[] args) {
Hello hello = new Hello();
hello.rl.run();
hello.r2.run();
}
}
}
你认为执行结果会显示“ Hello, World ”吗?看来并不是
如果 Lambda 表达式只是匿名类的语法蜜糖,那么结果也该是显示 cc.openhome. Hello$1@
15db9742 cc.openhome Hello$2@6d06d69c 之类的信息, 事实上,执行结果会是显示两次 Hello
world !” 就是说, Lambda 表达式中 this 的参考对象以及 toString ()(也就是 this. toString () )
接受者,是来自 ambda 周围环境 Context),也就是看 Lambda 表达式是在哪个名称范畴
(Scope),就能参考该范畴 内的名称, 变量或方法。
在上面的范例中,因为是 Hello 类包围了 Lambda 表达式, Lambda 达式可以参考类范畴
中的名称,范例中定义了 He llo toStr ng ()返回” ello world 字符串 ,因而执行时才会
显示两次 Hello, world !”
3.方法与构造函数参考
4.接口默认方法