一、Lambda表达式简介
Lambda
表达式是一个可以替代匿名内部类的语法糖,与匿名内部类相比,Lambda
表达式更加简洁、更加易读,并且让代码更加专注于业务逻辑。
语法糖就是让你用起来感觉很甜~
二、Lambda表达式语法
Lambda
表达式是由参数列表、箭头符号->
和具体业务实现代码组成的。其中,参数列表可以为空,或者可以有多个参数,还可以在参数列表中指定参数类型。箭头符号用于将参数列表与具体业务实现代码区分开来。具体业务实现代码可以是一个语句块,也可以是一条具体的表达式。
下面是Lambda
表达式的一般形式如下:
(parameter1, parameter2, ..., parameterN) -> { statement1; statement2; ... }
比如下面的Lambda
表达式表示,接收一个整型参数,返回该整型的平方:
x -> x * x
三、Lambda的特征
Lambda
表达式具有以下三个特征。
-
可选类型声明
Optional Type Declaration
Lambda
表达式中的参数类型可以不声明,编译器可以统一识别参数值。 -
可选参数圆括号
Optional Parenthesis
Lambda
表达式中的参数可以不使用圆括号包裹。 -
可选大括号
Optional Braces
Lambda
表达式中的表达式可以不使用大括号包裹。当
Lambda
表达式的函数体中仅有一行语句或者一个单独的表达式时,可以不使用大括号包裹函数体;
否则,必须使用大括号包裹函数体。
四、Lambda表达式和匿名内部类的区别
Lambda
表达式是一个可以替代匿名内部类的语法糖,使程序更加简洁易懂。与匿名内部类相比,Lambda
表达式有以下几个不同点:
-
类型推断处理
在
Lambda
表达式语法中的参数类型是隐式声明的。Java编译器会根据Lambda
表达式的上下文推断出参数类型的具体信息。而在匿名内部类中,由于它是一个类,因此所有参数类型都需要显示声明。 -
代码量更少
匿名内部类中的额外代码使得它更加冗长。而
Lambda
表达式的语法能够直接使用表达式参数,从而避免了额外的样板代码。 -
处理作用域
匿名内部类中的
this
关键字指向的是这个类实例本身,但是在Lambda
表达式中的this
关键字引用它所在的类实例。而这样就使得在Lambda
表达式中访问外部的变量比匿名内部类更加容易了。
五、Lambda表达式实现Runnable接口
在此之前,我们通常使用匿名内部类来达到达效果,Lambda
表达式则可以进一步优化代码。如下代码是Runnable
接口的匿名内部类实现,它可以开启一个线程:
Runnable r1 = new Runnable() {
public void run() {
System.out.println("Hello, World!");
}
};
new Thread(r1).start();
而使用Lambda
表达式实现以上示例,则可以简化该代码:
Runnable r2 = () -> System.out.println("Hello, World!");
new Thread(r2).start();
六、Lambda表达式实现Comparator接口
在使用Java集合框架中,Comparator
接口常用于比较集合中的元素。在使用Lambda
表达式之前,我们经常使用匿名内部类来实现Comparator
接口,并重写compare()
方法。而使用Lambda
表达式可以让代码更加简洁。比如下面的代码:
List<String> list = Arrays.asList("apple", "banana", "orange", "pear");
Collections.sort(list, new Comparator<String>() {
public int compare(String a, String b) {
return a.compareTo(b);
}
});
System.out.println(list);
可以使用Lambda
表达式重写以上代码:
List<String> list = Arrays.asList("apple", "banana", "orange", "pear");
Collections.sort(list, (a, b) -> a.compareTo(b));
System.out.println(list);
使用Lambda
表达式可避免了冗长的匿名内部类,代码更加简洁易读。
七、Lambda表达式和方法引用
Lambda
表达式可以进一步与方法引用结合使用,形式如下:
ClassName::methodName
其中ClassName
是所引用的类的名字,而methodName
是在这个类中所引用的方法的名字。
Lambda
表达式的方法引用形式有如下四种:
- 静态方法引用:
Function<String, Integer> toInteger = Integer::parseInt;
Integer number = toInteger.apply("1234");
- 实例方法引用:
String str = "Hello, World!";
Predicate<String> contains = str::contains;
System.out.println(contains.test("World"));
- 构造方法引用:
Supplier<Thread> threadSupplier = Thread::new;
Thread thread = threadSupplier.get();
thread.start();
- 数组引用:
Function<int[], Integer> arrayLength = int[]::length;
Integer length = arrayLength.apply(new int[] {1, 2, 3});
System.out.println(length);
八、Lambda表达式和Stream API
Java 8还新增了Stream API,一些特殊的Lambda
表达式和Stream API结合使用可以更好地发挥Lambda
表达式的性质。
示例代码:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream()
.filter(n -> n % 2 == 1)
.mapToInt(Integer::intValue)
.sum();
System.out.println(sum);
以上代码创建并使用了一个数列,使用了Stream API中的filter()
、mapToInt()
和sum()
方法,让代码变得更加简洁。
九、Lambda的使用场景
Lambda
表达式可以用于任何类型的接口,只要该接口只有一个抽象方法即可(即函数接口)。
在实际应用中,Lambda
表达式可以用于各种Java API,比如集合框架、Stream API、IO等,可以提高应用程序的效率和可读性。
Lambda
表达式可以优化以下几种场景:
- 优化匿名内部类
Lambda
表达式可以优化匿名内部类的语法,让代码更加精简。
- 避免过多的位置参数
在使用函数调用时,过多的位置参数会影响代码的可读性。而使用Lambda
表达式可以避免过多的位置参数。
- 简化集合类的方法
使用Lambda
表达式可以避免冗长的匿名内部类,并使得集合类的方法更加简洁易读。