使用前提

  1. 必须具有接口,且接口中有且仅有一个抽象方法。(如Runnable、Comparable)
  2. 必须具有上下文推断:方法的参数具有的类型必须为Lambda对应的接口类型,才能使用Lambda作该接口的实例。

有且仅有一个接口的抽象方法,称为函数式接口

格式

(参数表) -> {代码块(方法体)}

-> : 把参数传给方法体
{} : 重写接口的方法体

1
2
3
4
5
6
7
8
9
10
11
//普通写法
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
});
//Lambda写法
new Thread(()->{
System.out.println(Thread.currentThread().getName());
}).start();
1
2
3
4
5
6
7
8
9
10
11
//普通写法
invokeCalc(5, 6, new Calc() {
@Override
public int plus(int a, int b) {
return a + b;
}
});
//Lambda形式
invokeCalc(5, 6, (int a, int b)->{
return a + b;
});

Lambda的省略规则

可推导的都可以省略

  • 规则:
    • ()内参数的类型可以省略
    • 如果()内有且仅有一个参数,则()可以省略
    • 如果{}内有且仅有一个语句,则{}可省略,并且语句后面的;要一起省略,return也可省略。
    • func(()->{return a+b}); 省略为func(()->a+b)
1
2
3
// Lambda 省略形式
new Thread(()-> System.out.println(Thread.currentThread().getName())).start();
new Thread(()-> Thread.currentThread().getName()).start();
1
2
// Lambda 省略形式
invokeCalc(4,5,(a,b)-> a + b);

Lambda引用的局部变量必须是 final

闭包

闭包是一个函数的实例,可以无限制地访问那个函数的非本地变量。
闭包可以作为参数传递给另一个函数,也可以访问和修改其作用域之外的变量。
限制:不能修改定义Lambda的方法的局部变量的内容,这些变量必须是隐式的final的。
限制的原因是由于局部变量保存在栈上,并且隐式表示他们仅限于其所在的线程,如果改变会造成线程不安全的可能。

方法引用

根据已有的方法来创建Lambda表达式,如下getAge是Student内的一个方法。

构建方法引用的三种方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//1.指向静态方法的方法引用
//Integer的parseInt方法
Integer::parseInt

//2.指向**任意类型实例**的方法
//String的length方法
String::length

//3.指向**现有对象的实例方法**的方法引用
//Student类中存age的方法
Student::getAge

//4.构造方法引用
Supplier<Scholar> supplier = ()->new Scholar();//Lambda普通简化写法
Supplier<Scholar> supplier = Scholar::new;//使用方法引用 进一步简化
1
2
3
4
//普通写法
(Student a)->a.getAge()
//方法引用
Student::getAge
1
2
3
4
5
6
7
8
()->Thread.currentThread().dumpStack()
()->Thread.currentThread::dumpStack

(str, i)->str.substring(i)
String::substring

(String s)->System.out.println(s)
System.out::println