# 新特性简介
- 速度更快,便于并行
- 代码更少,增加了新的语法:Lambda 表达式
- 强大的 Stream API
- 最大化的减少空指针异常:Optional
- Nashorn 引擎,允许在 JVM 上运行 JS 应用
# Lambda 表达式
Lambda 表达式的本质:与其他语言的 lambda 表达式不同,java 中的 lambda 表达式不是匿名函数,而是作为函数式接口的实例。
以 (o1,02) -> Interger.compare(o1,o2)
为例, ->
是 Lambda 操作符或箭头操作符,左边是形参列表,其实就是接口中的抽象方法的形参列表,右边是 lambda 体,其实就是重写的抽象方法的方法体。
以前使用匿名实现类表示的现在都可以用 lambda 表达式做。
# 语法格式
//1.无参,无返回值
Runnable r2 = () -> System.out.println("hello,world");
//2.Lambda需要一个参数,但是没有返回值
Consumer<String> con = (String s) -> {System.out.println(s);};
//3.数据类型可以省略,因为可由编译器推断得出,称为“类型推断”,只有一个参数时可以省略小括号
Consumer<String> con = s -> {System.out.println(s);};
//4.表达式需要两个或以上的参数,多条执行语句,并且可以有返回值
Comparator<Integer> com = (o1,o2) -> {
System.out.println("========");
return o1.compareTo(o2);
};
//5.当lambda题只有一条语句时,return和大括号都可以省略
Comparator<Integer> com = (o1,o2) -> o1.compareTo(o2);
# 函数式接口
如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口。
我们可以在一个接口上使用 @FunctionalInterface
注解,这样可以检测它是否为函数式接口。
在 java.util.function 包下定义了 java8 丰富的函数式接口。
java 不仅可以支持 OOP (面向对象编程),还可以支持 OOF (面向函数编程)。
# 核心函数式接口
接口 | 参数类型 | 返回类型 | 用途 | 方法 |
---|---|---|---|---|
Consumer |
T | void | 对类型为 T 的对象应用操作 | void accept(T t) |
Supplier |
无 | T | 返回类型为 T 的对象 | T get() |
Function<T,R> | T | R | 对类型为 T 的对象应用操作,并返回结果为 R 的对象 | R apply(T t) |
Predicate |
T | boolean | 确定类型为 T 的对象是否满足某种约束,并返回 boolean 值 | boolean test(T t) |
# 方法引用和构造器引用
当要传递给 lambda 体的操作,已经有实现的方法了,可以使用方法引用。方法引用就是 lambda 表达式,通过方法的名字来指向一个方法,可以认为是 lambda 表达式的一个语法糖。
使用的要求是实现接口的抽象对象方法的参数列表和返回值类,必须与方法引用的方法的参数列表和返回值类型一致。
使用格式: 类或对象 :: 方法名
。具体有三种情况,对象调用非静态方法,类调用静态方法,类调用非静态方法。
//Consumer中的void accept(T t)和PrintStream中的void println(T t)的参数列表和返回值类型一致
Consumer<String> con1 = s -> System.out.println(s);
con1.accept("hello,world");
//使用方法引用
PrintStream ps = System.out;
Consumer<String> con2 = ps::println;
con2.accept("hello,beijing");
//类::实例方法,Comparator中的int compare(T o1,T o2)和String中的int o1.compareTo(o2)
//前者比后者多一个参数,实际上是使用该参数调用实例方法,因为类是无法调用实例方法的
Comparator<String> com = (o1,o2) -> o1.compareTo(o2);
Comparator<String> com2 = String :: compareTo;
//构造器引用与方法引用类似
Supplier<Employee> sup = () -> new Employee();
Supplier<Employee> sup1 = Employee::new;
# Stream API
Stream API 把真正的函数式编程风格引入到 java 中。使用 Stream API 可以对集合数据进行操作,可以执行非常复杂的查找、过滤和映射数据等操作,这操作类似 SQL 执行的数据库查询。
现在数据库源有 MongDB,Redis 等,而这些 NoSQL 的数据就需要 java 层面去处理。
Stream 和 Collection 集合的区别:Collection 是一种静态的内存数据结构,而 Stream 是有关计算的。前者主要面向内存,存储在内存中,后者主要是面向 CPU,通过 CPU 实现计算。
Stream 自身不存储元素。Stream 不会改变源对象,相反,他们会返回一个持有结果的新 Stream。
Stream 操作是延迟执行的,只有在执行终止操作,才执行中间操作链,并产生结果。执行终止操作后流不能再复用,若想继续操作需要重新创建新的 Stream。
Optional
# 创建 Stream 流
- 集合可以通过 stream () 方法返回一个顺序流,通过 parallelStream () 方法返回一个并行流。
- 数组可以通过 stream () 方法返回一个流。
- 通过 Stream 的 of () 方法,在方法内填入多个参数形成容器。
- 使用 iterate () 迭代方法和 generate () 生成方法创建无限流,主要用于生成数据。
List<Employee> employees = EmployeeData.getEmployees();//获取一个集合
//default Stream<E> stream():返回一个顺序流
Stream<Employee> stream = employees.stream();
Stream.of(1,2,3,4,6);//填入参数形成容器
//迭代方法,初始值为0,每次迭代加2,limit()限制输出个数,并在forEach()中指定输出位置
Stream.iterate(0,t -> t+2).limit(10)forEach(System.out::println);
Stream.generate(Math::random).limit(10)forEach(System.out::println);//生成10个随机数
# 中间操作
# 筛选与切片
方法 | 作用 |
---|---|
fliter(Predicate p) | 接收 Lambda,从流中排除某些元素 |
distinct() | 筛选,通过流所生成元素的 hashCode () 和 equals () 去除重复元素 |
limit(long maxSize) | 截断流,使其元素不超过给定数量 |
skip(long n) | 跳过元素,返回一个忽略前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。 |
# 映射与排序
方法 | 作用 |
---|---|
map(Function f) | 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。 |
mapToDouble(ToDoubleFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个 DoubleStream。 |
mapToint(TointFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个 IntStream。 |
mapToLong(ToLongFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个 LongStream。 |
flatMap(Function f) | 接收一个函数作为参数,将流中的每个值都转换成一个流,然后把所有流连接成一个流。例如将字符串数组的每个元素拆成字符,再组合成一个字符数组。 |
sorted(Comparator com) | 产生一个新流,如果没有传入比较器,则按自然顺序排序,否则按照比较器顺序排序。 |
# 终止
map 和 reduce 的连接通常被称为 map-reduce 模式,因 Google 用它来进行网络搜索而出名。
Collect 接口中方法的实现决定了如果对流执行收集的操作,如收集到 List,Set 和 Map。另外 Collects 实用类提供了很多静态方法,可以方便地创建常见收集器实例。
方法 | 作用 |
---|---|
allMatch(Predicate p) | 检查是否匹配所有元素 |
anyMatch(Predicate p) | 检查是否至少匹配一个元素 |
noneMatch(Predicate p) | 检查是否没有匹配所有元素 |
findFirst() | 返回第一个元素 |
findAny() | 返回当前流中所有元素 |
count() | 返回流中元素的总个数 |
max(Comparator c) | 返回流中元素的最大值 |
min(Comparator c) | 返回流中的最小值 |
forEach(Consumer c) | 内部迭代 |
reduce(T iden,BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值,返回 T。 |
reduce(BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值,返回 Optional |
collect(Collector c) | 将流转换为其他形式。接收一个 Collector 接口的实现,用于给 Stream 中元素做汇总的方法 |