本文已参与「新人创作礼」活动,一起开启掘金创作之路。
简介
Java 8 中出了很多新特性,比如 Lambda 表达式、函数式接口、方法引用、默认方法、Stream API、Optional 类......其中,我认为最主要的是Lambda表达式和Stream API这两个。
Lambda表达式又可以称为函数式编程,关注的是“做什么”,Lambda允许将函数作为一个方法的参数或者将代码看成数据进行使用。
说到 Stream,我们很容易想到 I/O Stream,可以简单理解 Stream 就是一个管道。我们能够通过这个管道提供的 API 对数据进行操作,比如过滤、去重、查找等。
好处
使用 Java 8 新特性主要有以下两个好处:
代码简洁:函数式编程使代码简洁且意图明确,比如 stream 接口让你告别 for 循环
(当然也有人觉得这样写没有那么易懂,个人觉得 Stream 学得好的都能秒懂)
List<String> list = new ArrayList<>();
// 在未使用 Stream 之前,你可能是这样遍历集合的
for (int i = 0; i < list.size(); i++) {
}
// 也可能是这样遍历集合
for (String s : list) {
}
// 使用 Stream 后,你就可以这么写了
list.forEach(item -> {});
多核友好:Java函数式编程使编写并行程序变得简单,只需调用 parallelStream() 或 parallel() 方法即可
List<String> list = new ArrayList<>();
// 串行方式
list.forEach(item -> {});
list.stream().forEach(item -> {});
// 并行方式
list.parallelStream().forEach(item -> {});
list.stream().parallel().forEach(item -> {});
Lambda
语法
- “->”:被称为lambda操作符或箭头操作符
- 参数(符号左侧):指定了lambda表达式需要的所有参数
- 方法体(符号右侧):指定了lambda体,即lambda表达式所要执行的任务、功能或行为
// 普通代码
@Test
public void testOOP() {
new Thread(
new Runnable() {
@Override
public void run() {
System.out.println("OOP");
}
}
).start();
}
// Lambda 表达式
@Test
public void testLambda() {
new Thread(
() -> System.out.println("OOP")
).start();
}
Stream
Stream 位于 java.util.stream,是对数据处理的一种抽象描述,支持并行执行。Stream API 提供了一种高效且易于使用的处理数据的方式,解决了已有集合类操作上的弊端。
Stream 理解
- 定义:支持数据处理操作的源生成的元素序列(就是能够将我们的数据还原为原来的样子并进行处理)
- 元素序列
- 可以访问特定元素类型的⼀组有序值
- 集合讲的是数据(存储):集合是数据结构,主要目的是以特定时间/空间复杂度存储和访问元素
- 流讲的是计算(处理):流的目的在于表达计算,比如filter、sorted、map等
- 源
- 流会使用⼀个提供数据的源,如集合、数组或输入/输出资源。
- 从有序集合生成流时会保留原有的顺序。
- 由列表生成的流,其元素顺序与列表⼀致。
- 数据处理操作
- 流的数据处理功能支持类似于数据库的操作以及函数式编程中的常用操作,比如filter、map、find等。
- 流操作可以顺序执行,也可以并发执行
假设砌墙的砖块都是由沙子、小石头等等组成的,那么 Stream 就是将这些砖块编程沙子、小石头,然后进行处理,从而产生一个新的砖块或者是其它东西。
Stream流的创建
- Collection 的默认方法 stream() 和 parallelStream()
- Arrays.stream()
- Stream.of()
- Stream.iterate():产生迭代无限流
- Stream.generate():产生无限流
常用API
-
筛选和切片
Stream<T> filter(predicate<T> p):过滤,根据 lambda 结果从流中过滤掉某些数据Stream<T> skip(long n):跳过 n 个数据Stream<T> distinct():去重,根据流中数据的 hashCode 和 equals 去除重复元素Stream<T> limit(long maxSize):保留指定个数的数据,不能超过流中数据总个数
-
映射
<R> Stream<R> map(Function<T, R> mapper):将给定函数应用到每个元素上,并将其映射成一个新的元素<R> Stream<R> flatMap(Function<T, Stream<R>> mapper):将流中每个值都换成另一个流,然后将所有流连接成一个流
-
排序
Stream<T> sorted():⾃然排序使用 Comparable的int compareTo(T o) ⽅法Stream<T> sorted(Comparator<T> comparator):定制排序使用 Comparator 的 int compare(T o1, T o2) ⽅法
-
查找匹配
Stream<T> sorted():⾃然排序使用 Comparable 的 int compareTo(T o) ⽅法Stream<T> sorted(Comparator<T> comparator):定制排序使用 Comparator 的 int compare(T o1, T o2) ⽅法
-
查找匹配
boolean allMatch(Predicate<T> predicate):检查是否匹配所有元素boolean anyMatch(Predicate<T> predicate):检查是否⾄少匹配⼀个元素boolean noneMatch(Predicate<T> predicate):检查是否没有匹配的元素Optional<T> findFirst():返回第⼀个元素Optional<T> findAny():返回当前流中的任意元素(⼀般用于并行流)
-
统计
long count():返回流中元素的总个数Optional<T> max(Comparator<T> comparator):返回流中最⼤值Optional<T> min(Comparator<T> comparator):返回流中最小值
-
汇总
<R,A> R collect(Collector<T,A,R> collector):将流转换为其他形式
-
分组和分区
-
Collectors.groupingBy():对元素做group操作。分组--根据条件分成多个组 -
Collectors.partitioningBy():对元素进⾏二分区操作。分区--根据boolean条件分成两个区
-