引言
Lambda 表达式是 Java SE 8 中一个重要的新特性。其允许你通过表达式来代替功能接口。 lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(可以是一个表达式或一个代码块)。 此外,Lambda 表达式也可以看作是一个匿名函数,基于数学中的 λ 演算得名,也称为闭包。
一、语法格式
基本语法
(parameters) -> expression;
或
(parameters) ->{ statements; };
Lambda表达式由三部分组成:
-
paramaters:类似方法中的形参列表,这里的参数即为函数式接口里的参数。这里的参数类型可以明确声明,也可不声明,可由 JVM 推断。此外,当只有一个paramaters时,可以省略掉其对应圆括号。
-
->:可理解为“被用于”的意思。
-
方法体:可以是表达式也可以是代码块,是函数式接口里方法的实现。代码块可返回一个值或什么都不返回,这里的代码块等同于方法的方法体。如果是表达式,也可以返回一个值或者什么都不返回。
二、理解函数式接口
定义
如果一个接口有且仅有一个抽象方法,那么该接口称为函数式接口。
注意:如果我们在某个接口中声明了 @FunctionalInterface 注解,那么编译器就会按照函数式接口的定义来要求该接口。显然,当我们定义了两个抽象方法,程序编译就会报错。下面为函数式接口的语法
@FunctionalInterface
interface NoParameterNoReturn {
void test(); //注意:只能有一个抽象方法
}
三、使用 Lambda 表达式
程序清单1:
interface NoParameterNoReturn{
void test();
}
public class Test1 {
public static void main(String[] args) {
//1. 正常实现一个接口
//一般来说,接口不能直接通过 new 来实例化对象
//但是我们可以通过 new 一个对象,相当于一个匿名内部类实现了此接口,
//并重写其方法
NoParameterNoReturn noParameterNoReturn = new NoParameterNoReturn() {
@Override
public void test() {
System.out.println("重写方法");
}
};
noParameterNoReturn.test();
System.out.println("-----------------");
//2. 使用 Lambda 表达式
NoParameterNoReturn noParameterNoReturn2 = () -> System.out.println("重写方法");
noParameterNoReturn2.test();
}
}
输出结果:
程序清单2:
/**
* 通过使用 Lambda 表达式来测试一些接口
*/
interface OneParameterNoReturn {
void test(int a);
}
interface MoreParameterNoReturn {
void test(int a,int b);
}
interface NoParameterReturn {
int test();
}
interface OneParameterReturn {
int test(int a);
}
interface MoreParameterReturn {
int test(int a,int b);
}
public class Test2 {
public static void main(String[] args) {
//1. 一个参数无返回值
//形式一
OneParameterNoReturn oneParameterNoReturn = (a)-> {System.out.println(a);};
//形式二
OneParameterNoReturn oneParameterNoReturn2 = a-> System.out.println(a);
oneParameterNoReturn2.test(10);
System.out.println("----------------------");
//2. 多个参数无返回值
//形式一
MoreParameterNoReturn moreParameterNoReturn = (int a, int b)->{
System.out.println(a+b);
};
//形式二
MoreParameterNoReturn moreParameterNoReturn2 = (a,b)-> System.out.println(a+b);
moreParameterNoReturn2.test(10,20);
System.out.println("----------------------");
//3. 无参数有返回值
//形式一
NoParameterReturn noParameterReturn = ()->{return 111;};
//形式二
NoParameterReturn noParameterReturn2 = ()->111;
System.out.println(noParameterReturn2.test());
System.out.println("----------------------");
//4. 一个参数有返回值
OneParameterReturn oneParameterReturn = (a)->a+5;
System.out.println(oneParameterReturn.test(100));
System.out.println("----------------------");
//5. 多个参数有返回值
MoreParameterReturn moreParameterReturn = (a,b)->a*b;
System.out.println(moreParameterReturn.test(5, 5));
}
}
输出结果:
四、变量捕获
程序清单3:
/**
* 变量捕获
*/
class Out{
public void function(){
System.out.println(123);
}
}
interface NoParameterNoReturn2 {
void test();
}
public class Test3 {
public static void main(String[] args) {
//1. 将 x 这个变量视为常量,或者这个 x 变量不能被修改
//这样一来,下面的匿名内部类才能捕获到变量 x
int x = 111;
//x = 999; //error
new Out(){
@Override
public void function() {
System.out.println("捕获变量: " + x);
}
}.function();
//2. 同理,下面是 Lambda 的变量捕获
int a = 333;
//a = 999; //error
NoParameterNoReturn2 noParameterNoReturn2 = ()->{
System.out.println("捕获变量:"+ a);
};
noParameterNoReturn2.test();
}
}
输出结果:
五、Lambda在集合当中的使用
程序清单4:
import java.util.ArrayList;
import java.util.Comparator;
import java.util.function.Consumer;
/**
* Lambda 表达式在集合当中的使用
*/
public class Test4 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("hello");
list.add("world");
list.add("nice");
/**
* 1. 打印出来 list 中的现有元素
* 方法一:
* 直接通过匿名内部类实现 Consumer 这个函数式接口
*/
list.forEach(new Consumer<String>() {
@Override
public void accept(String str) {
System.out.println(str);
}
});
System.out.println("---------------------");
//方法二:
//Lambda 表达式的应用
list.forEach(str -> System.out.println(str));
System.out.println("---------------------");
/**
* 2. 排序 list 中的现有元素
* 方法一:
* 直接通过 Comparator 这个函数式接口 new 一个对象
*/
list.sort(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
System.out.println(list);
System.out.println("---------------------");
//方法二:
//Lambda 表达式的应用
list.sort((o1, o2) -> o1.compareTo(o2));
System.out.println(list);
}
}
输出结果:
六、Lambda 表达式的优缺点
Lambda表达式的优点很明显,在代码层次上来说,使代码变得非常的简洁。缺点也很明显,代码不易读。
优点:
① 代码简洁,开发迅速
② 方便函数式编程
③ 非常容易进行并行计算
④ Java 引入 Lambda,改善了集合操作
缺点:
① 代码可读性变差
② 在非并行计算中,很多计算未必有传统的 for 性能要高
③ 不容易进行调试