JDK8新特性
Lambda表达式
lambda表达式是Java8新增特性,它可以用来简化匿名内部类的写法。注意:Lambda表达式只能简化函数式接口的匿名内部类的写法形式(lambda表达式是一个函数式接口的实例:只要一个对象时函数式接口的实例,那么该对象就可以用lambda表达式来表示,所以以前使用匿名实现类表示的现在都可以用lambda表达式来写)
lambda表达式的简化格式
(匿名内部类被重写方法的形参列表) -> {
被重写方法的方法体代码
}
lambda表达式的使用,分六种情况介绍:
// 情况一:无参,无返回值
Runnable r = () -> {
System.out.println("hello world");
};
// 情况二:需要一个参数,但没有返回值
Consumer con = (String s) -> {
System.out.println("hello world");
};
// 情况三:数据类型可以省略,因为可由编译器推断得出,称为“类型推断”
Consumer con = (s) -> {
System.out.println("hello world");
};
// 情况四:若lambda只需要一个参数时,参数的小括号可以省略
Consumer con = s -> {
System.out.println("hello world");
};
// 情况五:若lambda需要两个或以上的参数,多条执行语句,并且可以有返回值
Comparator com = (x, y) -> {
System.out.println(x + " " + y);
return x.compareTo(y);
};
// 情况六:若lambda方法体中只有一条语句时,return与大括号都可省略
Comparator com = (x, y) -> x.compareTo(y);
函数式接口
lambda表达式的目标类型必须是"函数式接口",函数式接口代表只包含一个抽象方法的接口。函数式可接口可以包含多个默认方法、类方法,但只能声明一个抽象方法。在函数式接口上都有一个 @FunctionalInterface
注解,该注解用于告诉编译器执行更严格检查——检查该接口必须是函数式接口,否则编译器就会报错
java.util.function 包下预定义了大量函数式接口,如以下四类核心接口:
函数式接口 | 包含方法 | 返回值类型 | 用途 |
---|---|---|---|
Function 函数型接口 |
apply(T t) |
R | 对参数进行处理转换,然后返回一个新的值 |
Consumer 消费型接口 |
accept(T t) |
void | 消费数据;对参数进行处理,不会返回处理结果 |
Predicate 断定型接口 |
test(T t) |
boolean | 对参数进行某种判断,然后返回一个boolean值 |
Supplier 供给型接口 |
get() |
T | 生产数据;该方法不需要传入参数,它会返回一个类型为T的对象 |
方法引用和构造器引用
如果lambda表达式的代码只有一条,还可以在代码块中使用方法引用和构造器引用
实例 | 说明 |
---|---|
类名::静态方法 | 函数式接口中被实现方法的全部参数传给该类方法作为参数 |
对象::实例方法 | 函数式接口中被实现方法的全部参数传给该方法作为参数 |
类名::实例方法 | 函数式接口中被实现方法的第一个参数作为调用者,后面的参数全部传给该方法作为参数 |
类名::new | 函数式接口中被实现方法的全部参数传给该构造器作为参数 |
- 可以在方法引用中使用this、super参数,例如this::equals等同于x->this.equals(x)
Stream接口
Stream API(java.util.stream)把真正的函数式编程风格引入到Java中,提供了一种高效且易于使用的处理数据的方式。它可以对集合进行操作,例如执行非常复杂的查找、过滤和映射数据等操作
集合讲的是数据,Stream讲的是计算
- Stream不会自己存储元素
- Stream不会改变原对象,它们会返回一个持有结果的新Stream
- Stream操作是延迟执行的,这意味着它们会等到需要结果的时候才执行
Stream操作的三个步骤:
- 创建Stream:根据一个数据源(如集合/数组),获取一个流
- 中间操作:对数据源的数据进行处理
- 终止操作:一旦执行终止操作,就执行中间操作链,并产生结果。之后不会再被使用
创建Stream流对象
- 方法一:通过集合,Collection中有一个默认的stream()方法
- default Stream
stream():返回一个顺序流 - default Stream
parallelStream():返回一个并行流
- default Stream
- 方法二:通过数组,Arrays中有一个静态stream()方法
- static
Stream stream(T[] array):返回一个流
- static
- 方法三:通过Stream接口的静态方法of()返回一个流
- 方法四:创建无限流;通过Stream接口的静态方法iterator和generate()方法
- 迭代:static
Stream iterate(final T seed,final UnaryOperator f) - 生成:static
Stream generate(Supplier s)
- 迭代:static
Stream的中间操作
多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会自行任何的处理。而在终止操作时一次性全部处理,称为“惰性求值”
筛选和切片 | 说明 |
---|---|
filter(Predicate p) | 从流中排除某些元素 |
distinct() | 去重 |
limit(long maxSize) | 使元素不超过给定的数量 |
skip(long n) | 跳过元素 |
映射 | 说明 |
---|---|
map(Function f) | |
mapToDouble(ToDoubleFunction f) | |
mapToInt(ToIntFunction f) | |
mapToLong(ToLongFunction f) | |
flatMap(Function f) |
排序 | 说明 |
---|---|
sorted() | 按自然顺序排序 |
sorted(Comparator com) | 按比较器顺序排序 |
终止操作
终止操作会从流的流水线生成结果。流终止操作后,不能再次使用
匹配与查找 | 说明 |
---|---|
allMatch(Predicate p) | 检查是否匹配所有的元素 |
anyMatch(Predicate p) | 检查是否至少匹配一个元素 |
noneMatch(Predicate p) | 检查是否没有匹配所有元素 |
findFirst() | 返回第一个元素 |
findAny() | 返回当前流中的任意元素 |
forEach(Consumer c) | 内部迭代 |
max(Comparator c) | 返回流中最大值 |
min(Comparator c) | 返回流中最小值 |
count() | 返回流中元素总数 |
归约 | 说明 |
---|---|
reduce(T iden,BinaryOperator b) | 将流中元素反复结合起来,得到一个值 |
reduce(BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值 |
补充:map和reduce的连接通常称为map-reduce模式,Google用它来进行网络搜索而出名
收集 | 说明 |
---|---|
collect(Collector c) | 将流转换为其他形式 |
Collectors提供了很多静态方法,可以方便地创建常见集合实例
Optional类
空指针异常时导致Java应用程序失败的最常见原因,JDK8引入Optional类来检查空值,防止代码污染
Optional
……待续