Lambda表达式
转载请标注出处: Lambda表达式
Lambda 是一个匿名函数, Lambda 允许把函数作为一个方法的参数(函数作为参数传递到方法中)。 这使得我们可以写出更简洁、 更灵活的代码。
以一个匿名内部类转换到 Lambda 表达式的案例,体会 Lambda 表达式的简洁。
假设有以下情景。
目前有一个 ArrayList 类型的 strings 字符串链表,我们已经在里面插入了数据,现在我们需要对其中的字符串进行自定义的排序。在日常编写代码的时候,排序往往是经常出现的,我们需要调用sort,但为了能够实现自定义排序,我们必须重写 Comparator 的 compare 方法。
List<String> strings=new ArrayList<>();
//... 省略插入数据
strings.sort(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
//根据情况返回 -1, 0, 1。
return 0;
}
});
我们可以看到使用匿名内部类的写法相对于重新创建一个新类再传入已经简洁了不少了。但依旧是想当繁琐,我们接下来看,等价转化为使用 Lambda 表达式的代码。
ArrayList<String> strings=new ArrayList<>();
//... 省略插入数据
strings.sort((o1, o2) -> {
//根据情况返回 -1, 0, 1。
return 0;
});
比较一下使用匿名内部类和使用 Lambda 的代码,我们可以深切感受到使用 Lambda 可以简化代码。接下来我们学习一下 Lambda 的基本语法。
基本语法
Lambda 语法的关键在于引入的 -> 操作符,此操作符的左边的 ( ) 为 Lambda 所需要的参数,右边的 { } 为 Lambda 体,即 Lambda 表达式要执行的代码。
Lambda 表达式的语法格式如下
(parameters) -> expression
或
(parameters) ->{ statements; }
我们在使用 Lambda 表达式的时候,根据 Lambda 体内需要执行的代码数量选择不同的格式,如果是仅需要一行则选择不带 { } 的那种,反之则是带 { } 的。而前面的 ( ) 也是如此。
接下来给出 Lambda 表达式的一些例子。
Lambda 的例子
- 无返回值,无参数的 Lambda 表达式
Run1 runnable1 = () -> System.out.println("Hello");
我们来看这个对 Lambda 表达式的使用,其中 Run1 是一个接口,这个是我为了能够方便展示代码而捏造的一个接口。所有接口的定义在例子的结尾给出,此时我们不必关注这个点。这个 Lambda 表达式非常简单,就是输出一个Hello的语句。而我们的 run1 对象则是使用 Lambda 表达式来初始化自己。
- 无返回值,单个参数的 Lambda 表达式
Run2 run2 = (int x) -> System.out.println(x);
Run2 run2 = (x) -> System.out.println(x);
再来看这个例子,我们这里的 Lambda 表达式有了参数,这使得我们可以改变打印出来的值。
我们先来看第一行的 Lambda 表达式,这里的 Lambda 表达式的参数是带有类型,并不是说 Lambda 表达式一开始的参数就是不需要写类型的,而是因为 Java 8 引入的类型推断新特性而使得编译器有了推断类型的能力,这使得我们不需要去写类型,而是由编译器自动推导得出。这样才使得第一行代码能够简化为第二行的代码。
根据我们之前提到的 Lambda 表达式在单一参数下是可以省略括号的原则。我们先省去 ( )。变成如下代码。
Run2 run2 = x -> System.out.println(x);
我们可以使用方法引用特性进一步优化。
Run2 run2 = System.out::println;
方法引用这一语法特性也是 Java 8 中的新特性,这里我们只是提及,在之后会详细介绍。
- 无返回值,多个参数的 Lambda 表达式
Run3 run3 = (x,y) -> System.out.println(x+y);
有了前两个例子作铺垫,现在应该是非常容易能够理解这个多参数类型的 Lambda 表达式。此表达式的作用是打印两个参数之和。
- 有返回值,多个参数的 Lambda 表达式
Run4 run4 = (x,y) -> {return x+y;};
这个写法是最原始的一种写法,因为 return 语句不能和单一语句一样不需要大括号。而是需要像代码块一样,用大括号包起来。我们如果将 { } 去掉,并且去掉 return ,可以简化为以下代码。
Run4 run4 = (x,y) -> x+y;
而如果使用方法引用,代码将会更加简洁。
Run4 run4 = Integer::sum;
不管是 Lambda 表达式还是方法引用,目的都是为了简化代码。其中方法引用只能引用现有的方法,而 Lambda 表达式是一个全新的方法。
全部代码展示
public class Main {
public static void main(String[] args) {
Run1 run1 = () -> System.out.println("Hello");
Run2 run2 = (x) -> System.out.println(x);
Run3 run3 = (x,y) -> System.out.println(x+y);
Run4 run4 = Integer::sum;
}
interface Run1{
void func();
}
interface Run2{
void func(int x);
}
interface Run3{
void func(int x,int y);
}
interface Run4{
int func(int x,int y);
}
}
总结一下 Lambda 表达式的特点
- 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
- 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
- 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
- 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定表达式返回了一个数值。