Java是面向对象编程而不是面向函数编程,是不能把方法名作为参数传递给一个方法的,若想把一个行为作为参数传递给方法,只能采用匿名类的形式,非常繁琐,如下:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Before Java8, too much code for too little to do");
}
}).start();
Java SE 8出现了Lambda表达式,可以使用函数式风格编程,将取代匿名类,例如上面的代码可以改成这样:
new Thread( () -> System.out.println("In Java8, Lambda expression rocks !!") ).start();
注意事项:
1.只有接收函数式接口作为参数的方法,才能放入Lambda表达式,函数式接口即只有一个抽象方法的接口,常用@Functional注释
2.Lambda只能捕获final变量,所以不能在Lambda表达式内部修改定义在域外的变量,也不能捕获到那些可能会发生变化的变量
3.Lambda表达式中的this不是指接口实例的this,而是指创建Lambda表达式的方法所在类的this
4.Lambda表达式与包含它的方法有相同的作用域,所以也存在参数命名冲突的问题
Lambda表达式语法:
//完整写法
(String first, String second) -> first.length() - second.length()
//完整写法(加代码块)
(String first, String second) -> {//可以有返回值,取决于接口中定义的抽象方法是否有返回值}
//没有参数要提供空括号
() -> {...}
//如果可以推导出参数类型,那么参数类型可省略
(first, second) -> first.length() - second.length()
//如果方法只有一个参数且类型可推导出,还可以省略小括号
x -> {...}
方法引用
例如:
System.out::println
//等价于
x -> System.out.println(x)
有三种引用方式:
object::instanceMethod
Class::staticMethod
//第一个参数将作为object
Class::instanceMethod
此外还有构造器引用:
Class::new
Lambda表达式应用实例
1.实现Runnable接口
new Thread( () -> System.out.println("In Java8, Lambda expression rocks !!") ).start();
2.列表迭代
//features为一列表对象
features.forEach(n -> System.out.println(n));
3.事件处理
show.addActionListener((e) -> {
System.out.println("Light, Camera, Action !! Lambda expressions Rocks");
});
常用函数式接口
函数式接口 | 参数类型 | 返回类型 | 抽象方法名 | 描述 |
Runnable | 无 | void | run | 作为无参数无返回值的动作运行 |
Supplier<T> | 无 | T | get | 提供一个T类型的值 |
Consumer<T> | T | void | accept | 处理一个T类型的值 |
BiConsumer<T,U> | T,U | void | accept | 处理T和U类型的值 |
Function<T,R> | T | R | apply | 有一个T类型参数返回R类型值的函数 |
BiFunction<T,U,R> | T,U | R | apply | 有T和U类型参数返回R类型值的函数 |
UnaryOperator<T> | T | T | apply | 类型T上的一元操作符 |
BinaryOperator<T> | T,T | T | apply | 类型T上的二元操作符 |
Predicate<T> | T | boolean | test | 有一个T类型参数的布尔值函数 |
BiPredicate<T> | T,U | boolean | test | 有两个T类型参数的布尔值函数 |