新特性01| Lambda 表达式

简介

Lambda expressions basically express instances of functional interfaces (An interface with single abstract method is called functional interface. An example is java.lang.Runnable). lambda expressions implement the only abstract function and therefore implement functional interfaces.
lambda expressions are added in Java 8 and provide below functionalities.

  • Enable to treat functionality as a method argument, or code as data.
  • A function that can be created without belonging to any class.
  • A lambda expression can be passed around as if it was an object and executed on demand.

(译文)Lambda表达式一般用来表示函数式接口(有且仅有一个抽象方法的接口被称为函数式接口,比如java.lang.Runnable)。lambda表达式实现了唯一的抽象方法,即实现了函数式接口。
Java8中添加的lambda表达式提供了以下功能:

  • 将方法看作是传入方法的参数,或是将代码看作数据;
  • 可以创建一个不属于任何类的方法;
  • lambda表达式可以像传递对象一样传递,并按需执行。

说明

基于JVM的很多语言一开始就支持Lambda表达式,而在Java8之前Java采用的是匿名内部类。使用时需要明白以下2点:

  1. Lambda表达式主要用来定义行内执行的方法类型接口,比如下面简单用法举例additionsubtractionmultiplicationdivisiongreetService1greetService2的使用。

  2. Lamdba表达式省略了匿名内部类的麻烦,提供给Java一种函数式编程方法。

语法

1
2
3
(parameters) -> expression //expression只有一行
or
(parameters) ->{expression; ...; expression;} //expression有多行
  • 可不指定参数类型:编译器可自动识别;
  • 传入的参数可不用( )包围:如果只有一个参数不需( ),多个需要( );
  • 表达式部分可不用{ }包围:一行可不写{},多行需要{ };
  • 可不写return关键词:没写{ }的表达式会自动返回值,有{ }的表达式需要明确用return表明要返回的值;

简单用法举例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public class Java8Tester {
public static void main(String[] args) {
Java8Tester tester = new Java8Tester();

// 声明参数类型
MathOperation addition = (int a, int b) -> a + b;

// 不声明参数
MathOperation subtraction = (a, b) -> a - b;

// 用大括号包裹返回语句
MathOperation multiplication = (int a, int b) -> {
return a * b;
};

// 不用大括号包裹返回语句
MathOperation division = (int a, int b) -> a / b;

System.out.println("10 + 5 = " + tester.operate(10, 5, addition));
System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));
System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));
System.out.println("10 / 5 = " + tester.operate(10, 5, division));

// 不用括号
GreetingService greetService1 = message ->
System.out.println("Hello " + message);

// 用括号
GreetingService greetService2 = (message) ->
System.out.println("Hello " + message);

greetService1.sayMessage("Runoob");
greetService2.sayMessage("Google");
}

interface MathOperation {
int operation(int a, int b);
}

interface GreetingService {
void sayMessage(String message);
}

private int operate(int a, int b, MathOperation mathOperation) {
return mathOperation.operation(a, b);
}
}

运行结果

1
2
3
4
5
6
10 + 5 = 15
10 - 5 = 5
10 x 5 = 50
10 / 5 = 2
Hello Runoob
Hello Google

变量作用域

  1. 需要注意的是Lambda表达式只能引用外部final类型的变量,即不能在lambda内部修改定义在外部的final变量,否则导致编译错误
  2. 另一方面也说明在lambda表达式中使用的变量即使未显示声明为final,也是默认final的,否则是用不了的;
  3. 在Lambda表达式当中不允许声明一个与局部变量同名的参数或者局部变量,重复定义会导致编译错误。比如:
    1
    2
    String first = "";
    Comparator<String> comparator = (first, second) -> Integer.compare(first.length(), second.length()); //编译会出错

代码验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Java8Tester2 {
private final static String salutation = "Hello! ";

public static void main(String[] args) {
GreetingService greetService = message -> {
// salutation = "Hi!";
System.out.println(salutation + message);
};

greetService.sayMessage("Runoob");

}

interface GreetingService {
void sayMessage(String message);
}
}

输出结果

1
Hello! Runoob

但如果将上面代码中的注释符去掉,就会出现下面报错的情况:
编译错误:不能在 lambda 内部修改定义在域外的局部变量


更多详细内容参见官方文档

码哥 wechat
欢迎关注个人订阅号:「码上行动GO」