0 - Java8新特性思维导图
1 - lambda表达式
就是个匿名函数
. 只有函数式接口
(只有一个抽象方法的接口或者抽象类)才能使用.
1.1 - 语法
arg1, arg2 -> arg1 == arg2
参数列表 lambda主体
Java8中有效的lambda表达式:
1. str -> str.length() : 主体只有表达式, 隐含了return
2. (x, y) -> {
System.out.println(x);
System.out.println(y);
}
主体部分有多行, 使用{}. 如果主体部分是有效Java语句, 即时是一行也必须使用{}
3. () -> 17600221301: 没有参数, 返回一个int
1.2 - 函数描述符
定义: 函数式接口的方法签名, 也是lambda表达式的签名.
函数描述符用来描述lambda和函数式接口的签名. 比如Runnable接口的run方法, 他的函数描述符就是() -> void
. 从这个描述符中可以看出来, 这个方法不接收任何参数, 也不返回任何东西.
函数式接口常常带有这个注解. 用来表示这个接口被设计成函数式接口. 如果不是函数式接口, 那么编译器就会报错. 即: 加了@FunctionalInterface
注解的接口, 只能有一个抽象方法.
1.3 - 常见函数式接口
Java 8 在java.util.funcion
包中提供了一些新的函数式接口.
- Predicate:
- Consumer
- Function
1.4 - 类型检查/类型推断
1.4.1 - 类型检查
lambda的类型检查, 是根据lambda上下文推断出来的. lambda表达式需要的类型称为目标类型. 下面通过一个例子看下类型检查的过程.
List<Apple> apples = filter(inventory, (a) -> a.getWeight() > 150);
filter方法的定义为: filter(list inventory, Predicate a)
- 确定目标类型. 目标类型是Predicate
- 确定函数式接口的函数描述符. 这里的Predicate的test方法, 接收Apple类型参数a, 返回boolean. 即 Apple -> boolean.
- 确定lambda的签名, 是否符合第二步的函数描述符.
只要lambda的签名, 和目标函数描述符一致, 即可通过类型检查
1.4.2 - 类型推断
通过目标类型(函数式接口中方法的函数描述符)来推断出lambda表达式的正确签名. 这样就可以在lambda表达式中省去参数类型.
也就是说, 只要保证
1. 函数式接口中的方法的签名(函数描述符)
2. lambda表达式的签名(lambda的函数描述符)
这两个函数描述符一致, 就能通过类型检查. 同时, 也是根据1的函数描述符, 推断出lambda的参数类型, 从而省略参数类型, 只保留参数名.
1.4.3 - 使用局部变量
lambda表达式内部, 可以使用外部的局部变量. 但是这个局部变量必须是final或者事实上的final(只被赋值过一次).
1.5 - 方法引用
1.5.1 - 概念
定义: 根据对象中现有的方法来创建lambda表达式. 方法引用也是一种lambda表达式, 是lambda的快捷写法.
语法:
类名::方法名
方法名后面不用加(), 因为方法引用并没有真正的去调用这个方法. 比如Apple::getWeight这个方法引用, 其实就是
a -> a.getWeight()
的一种快捷写法.
1.5.2 - 写法
方法引用主要有三类:
- 指向静态方法的方法引用(eg: Integer::parseInt).
- 指向实例方法的方法引用
a. 引用对象的实例方法, 而这个对象是lambda的参数.
b. 引用对象的实例方法, 而这个对象是lambda外部的变量.
第1类
lambda clazz -> Class.forName(clazz)
方法引用 Class::forName
2.a类
lambda s -> s.length()
方法引用 String::length
2.b类
lambda () -> str.length()
方法引用 String::length
1.5.3 - 构造方法引用
类名::new