一、背景
在java8之前对于单个函数的封装常常使用匿名函数形式。
//单函数接口
public interface ActionListener {
void actionPerformed(ActionEvent e);
}
//因为它只会在调用处被使用一次。用户一般会使用匿名类型把行为内联(inline)
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ui.dazzle(e.getModifiers());
}
});
在java8出现之后,Java提供一种尽可能轻量级的将代码封装为数据(Model code as data)的方法,那就是函数式接口编程,可以替代匿名函数复杂且难懂的编程模式。
二、函数式接口
- 概念:只拥有一个方法的接口称为函数式接口。
- 在java8中通过@FunctionalInterface 注解来显式指定一个接口是函数式接口(以避免无意声明了一个符合函数式标准的接口),加上这个注解之后,编译器就会验证该接口是否满足函数式接口的要求。
- 现有的类库大量使用了函数式接口,通过沿用这种模式,我们使得现有类库能够直接使用 lambda 表达式,下面列举了常用的函数式接口:
- [java.lang.Runnable]
- [java.util.concurrent.Callable]e.html)
- [java.security.PrivilegedAction]
- [java.util.Comparator]
- [java.io.FileFilter]
- [java.beans.PropertyChangeListener]
- 以及java.util.function包中的常用函数式接口:
Predicate<T>——接收 T 并返回 boolean
Consumer<T>——接收 T,不返回值
Function<T, R>——接收 T,返回 R
Supplier<T>——提供 T 对象(例如工厂),不接收值
UnaryOperator<T>——接收 T 对象,返回 T
BinaryOperator<T>——接收两个 T,返回 T
三、lambda表达式
- 概念:lambda表达式是匿名方法,它提供了轻量级的语法,从而解决了匿名内部类带来的“高度问题”。(高度问题指的是在复杂的代码中实际工作的就那么几行代码)
1、举例说明
(int a, int b) -> { return a + b; }
() -> System.out.println("Hello World");
(String s) -> { System.out.println(s); }
() -> 42
() -> { return 3.1415 };
2、语法
lambda 表达式的语法由参数列表、箭头符号 -> 和函数体组成。函数体既可以是一个表达式,也可以是一个语句块:
- 表达式:表达式会被执行然后返回执行结果。
- 语句块:语句块中的语句会被依次执行,就像方法中的语句一样——
return 语句会把控制权交给匿名方法的调用者
break 和 continue 只能在循环中使用
如果函数体有返回值,那么函数体内部的每一条路径都必须返回值
3、lambda表达式讲解
1、一个 Lambda 表达式可以有零个或多个参数
2、参数的类型既可以明确声明,也可以根据上下文来推断。例如:(int a)与(a)效果相同
3、所有参数需包含在圆括号内,参数之间用逗号相隔。例如:(a, b) 或 (int a, int b) 或 (String a, int b, float c)
4、空圆括号代表参数集为空。例如:() -> 42
5、当只有一个参数,且其类型可推导时,圆括号()可省略。例如:a -> return a*a
6、Lambda 表达式的主体可包含零条或多条语句
7、如果 Lambda 表达式的主体只有一条语句,花括号{}可省略。匿名函数的返回类型与该主体表达式一致
8、如果 Lambda 表达式的主体包含一条以上语句,则表达式必须包含在花括号{}中(形成代码块)。匿名函数的返回类型与代码块的返回类型一致,若没有返回则为空
4、方法引用
- lambda 表达式允许我们定义一个匿名方法,并允许我们以函数式接口的方式使用它。我们也希望能够在 已有的 方法上实现同样的特性。
- 方法引用和 lambda 表达式拥有相同的特性(例如,它们都需要一个目标类型,并需要被转化为函数式接口的实例),不过我们并不需要为方法引用提供方法体,我们可以直接通过方法名称引用已有方法。
- 方法引用种类:
静态方法引用:ClassName::methodName
实例上的实例方法引用:instanceReference::methodName
超类上的实例方法引用:super::methodName
类型上的实例方法引用:ClassName::methodName
构造方法引用:Class::new
数组构造方法引用:TypeName[]::new
四、总结
java8提供的语言新特性并不多有lambda 表达式,方法引用,默认方法和静态接口方法等,如果把这几个特点结合起来并配置stream等新特性,开发者可以编写出更加清晰简洁的代码,类库编写者可以编写更加强大易用的并行类库。
参考资料:
http://zh.lucida.me/blog/java-8-lambdas-insideout-language-features/
http://www.importnew.com/11908.html
http://www.importnew.com/16436.html