二、Lambda表达式
Lambda表达式是一个可传递的代码块,可以在以后执行一次或多次。
Lambda表达式允许你通过表达式来代替功能接口(接口的实现放在Lambda表达式中,可以取代匿名类),Lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块)
1、基本语法
(parameters) -> expression 或 (parameters) ->{ statements; }
①选类型声明:不需要声明参数类型,编译器可以统一识别参数值
②可选参数的圆括号:一个参数无需定义圆括号,但是多个参数需要定义圆括号
③可选的大括号:如果主体包含了一个语句,就不需要使用大括号
④可选的返回关键字:如果主体只有一个表达式返回值,则编译器自动返回值,大括号需要指明表达式返回了一个数值。
简单的Lambda实例
// 1. 不需要参数,返回值为 5
() -> 5
// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y
// 4. 接收2个int型整数,返回他们的和
(int x, int y) -> x + y
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
2、方法引用
有时,可能已经有现成的方法可以完成你想要的传递到其它代码的某个动作
如
Timer t = new Timer(1000,event->System.out.println(event));
Timer t = new Timer(1000,System.out::println); //直接把println方法传递到Timer的构造器中
表达式System.out::println是一个方法引用
方法的引用有三种情况
Object::instanceMethod
Class::staticMethod
Class::instanceMethod
在前2中情况,方法的引用等价于提供方法参数的lambda表达式
如System.out::println等价于x->System.out.println(x)
Math::pow 等价于(x,y)->Math.pow(x,y)
对于第三种情况,第一个参数会成为方法的目标
String::compareToIgnoreCase等价于(x,y)->x.compareToIgnoreCase(y)
3、函数式接口
对于只有一个抽象方法的接口,需要这种接口对象时,就可以提供一个Lambda表达式,这种接口称为函数式接口。(Lambda表达式提供了接口内的方法实现)
①代替匿名内部类
使用匿名内部类
@Test
public void oldRunable() {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("The old runable now is using!");
}
}).start();
}
使用Lambda表达式
@Test
public void runable() {
new Thread(() -> System.out.println("It's a lambda function!")).start();
}
runnable只有一个抽象方法
②使用Lambda表达式对集合进行迭代
@Test
public void iterTest() {
List
//before java8
for(String each:languages) {
System.out.println(each);
}
//after java8
languages.forEach(x -> System.out.println(x));
languages.forEach(System.out::println);
}
③用Lambda表达式实现map
@Test
public void mapTest() {
List
cost.stream().map(x -> x + x*0.05).forEach(x -> System.out.println(x));
}
所得结果
10.5
21.0
31.5
Map的作用是将一个对象变换成另一个
reduce的作用是将所有值合并为一个
④使用Lambda表达式实现map和reduce
@Test
public void mapReduceTest() {
List
double allCost = cost.stream().map(x -> x+x*0.05).reduce((sum,x) -> sum + x).get();
System.out.println(allCost);
}
结果为63.0
⑤filter过滤操作
@Test
public void filterTest() {
List
List
filteredCost.forEach(x -> System.out.println(x));
}
4、构造器的引用
构造器的引用和方法的引用很相似,只不过方法名为new,如Person::new是Person构造器的一个引用,具体哪一个构造器取决于上下文
ArrayList
Stream
List
5、变量的作用域
lambda表达式有3个部分
①一个代码块
②参数
③自由变量的值,这里指非参数而且不在代码中定义的变量。
在lambda表达式中,只能引用值而不会改变变量。,表达式捕获的变量必须实际上是最终变量(这个变量在初始化之后就不会再为它赋值),lambda表达式中不能有同名的局部变量。