Stream 流是简化集合和数组操作的一种编程方式,使得集合和数组的操作像水流一样流畅。
下面通过 原理 + 实战 的方式了解 Stream 的用法。
获取方式
- 集合:default Stream
stream(); - 数组:
- Arrays.stream(T[] array);
- Stream.of(T… values); (可变参数可以接收数组作为参数)
```java
// 1. 集合
Collection
list = new ArrayList<>(); Stream ss = list.stream();
// 2. 数组
String[] arrs = new String[]{“Java”, “Python” ,”C”};
Stream
<a name="rwfWZ"></a>
# Stream 操作分类
1. 中间操作(intermediate):通过一系列中间(Intermediate)方法,对数据集进行过滤、检索等数据集的再次处理。
1. 中间操作的特点是方法返回值还是 Stream 类型,可以继续链式调用其他方法执行操作。
1. 中间操作是对数据的加工,注意,中间操作是 lazy 操作,并不会立马启动,需要等待终止操作才会执行。
2. 终止操作(Terminal):通过最终(terminal)方法完成对数据集中元素的处理。
1. 终止操作的特点是方法返回值为 空 或者 一个其他类型的结果。
1. 终止操作是 Stream 的启动操作,**只有加上终止操作,Stream才会真正的开始执行**。
- 无状态(Stateless):指元素的处理不受之前元素的影响;
- 有状态(Stateful):指该操作只有拿到所有元素之后才能继续下去。
- 非短路操作(Unshort-circuiting):指必须处理所有元素才能得到最终结果;
- 短路操作(Short-circuiting):指遇到某些符合条件的元素就可以得到最终结果,如 A || B,只要A为true,则无需判断B的结果。
![](https://cdn.nlark.com/yuque/0/2021/jpeg/12568777/1623808494277-f6acce55-4e76-41d8-809f-2184936f72a1.jpeg)
<a name="vVBCV"></a>
## 测试集合
Stream 中间操作不会自己启动,所以测试中都会加上 forEach 终止操作来启动 Stream 流的执行。
```java
List<String> list = Arrays.asList("Java", "", "Spring", "Mysql", "Python", "", "C++");
中间操作
filter
【中间操作】过滤元素,筛选 Stream 流中符合条件的元素,作为流返回。
定义:
Stream<T> filter(Predicate<? super T> predicate);
示例:找出集合中的空元素
list.stream().filter(String::isEmpty).forEach(System.out::println);
map
【中间操作】对 Stream 流中的元素执行指定操作后映射为新的值流返回(会改变之前的集合元素),相当于加工。
定义:
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
示例:将集合中的元素变为大写
list.stream().map(String::toUpperCase).forEach(System.out::println);
peek
【中间操作】返回一个由该流的元素组成的流,另外在每个元素上执行提供的操作,因为元素从结果流中被消耗。(Consumer 没有返回值,不会改变原来 Stream 流中的值)
定义:
Stream<T> peek(Consumer<? super T> action);
示例:源码中的说明
@apiNote This method exists mainly to support debugging, where you want to see the elements as they flow past a certain point in a pipeline: 此方法的存在主要是为了支持调试,您希望在其中查看元素流经管道中的某个点时的情况:
list.stream()
.filter(e -> e.length() > 3)
.peek(e -> System.out.println("Filtered value: " + e))
.map(String::toUpperCase)
.peek(e -> System.out.println("Mapped value: " + e))
.forEach(System.out::println);
limit
【短路有状态中间操作】截取 Stream 流中前 maxSize 个 元素。
定义:
Stream<T> limit(long maxSize);
示例:取集合中前 4 个元素。
list.stream().limit(4).forEach(System.out::println);
skip
【有状态中间操作】在丢弃流的前 n 元素后,返回由该流的其余元素组成的流。 如果此流包含少于 n 元素,则将返回一个空流。
定义:
Stream<T> skip(long n);
示例:跳过集合中前 4 个元素。
list.stream().skip(4).forEach(System.out::println);
distinct
【有状态中间操作】返回由该流的不同元素(根据Object.equals(Object) )组成的流。
- 对于有序流,不同元素的选择是稳定的(对于重复元素,保留遇到顺序中最先出现的元素。)
- 对于无序流,没有稳定性保证。
定义:
Stream<T> distinct();
示例:去除集合中重复的元素。
list.stream().distinct().forEach(System.out::println);
sorted
【有状态中间操作】返回由该流的元素组成的流,按自然顺序排序。
- 如果此流的元素不是 Comparable ,则在执行终端操作时可能会抛出java.lang.ClassCastException 。
- 对于有序流,排序是稳定的。 对于无序流,没有稳定性保证。
- 定义:
```java
Stream
sorted();
Stream
2. 示例:按照 自然排序/自然排序倒序 集合中的元素。
```java
list.stream().sorted().forEach(System.out::println);
// 还可以实现 Comparator 接口来自定义排序规则
list.stream().sorted(Comparator.reverseOrder()).forEach(System.out::println);
终止操作
forEach
【终止操作】遍历操作,依次遍历 Stream 流中的元素,并执行给定的行为。
定义:
void forEach(Consumer<? super T> action);
示例:遍历集合中的元素 ```java list.stream().forEach(System.out::println);
// 集合只遍历可简写为 Collection 自带的 forEach() 方法 // list.forEach(System.out::println);
<a name="zOYe5"></a>
### toArray
【终止操作】返回一个包含此流元素的数组。
1. 定义:
```java
Object[] toArray();
- 示例:将集合转成数组。 ```java Object[] strs = list.stream().toArray();
String[] strs = list.stream().toArray(String[]::new);
// 对于集合可简写为 Collection 自带的 toArray() 方法 // list.toArray();
<a name="atBXX"></a>
### min/max
【终止操作】返回 Stream 流中最小/最大的元素
1. 定义:
```java
Optional<T> min(Comparator<? super T> comparator);
Optional<T> max(Comparator<? super T> comparator);
- 示例:返回集合中最小/最大的元素
```java
Optional
min = list.stream().min(Comparator.naturalOrder()); System.out.println(min.get());
Optional
<a name="jMNfr"></a>
### count
【终止操作】返回此流中元素的计数。
1. 定义:
```java
long count();
- 示例:统计集合中的元素个数 ```java long size = list.stream().count();
// 对于集合可简写为 Collection 自带的 size() 方法 // list.size();
<a name="Bf4mV"></a>
### reduce
【终止操作】使用提供的标识值和关联累积函数对该流的元素执行归约,并返回归约后的值。
1. 定义:
```java
T reduce(T identity, BinaryOperator<T> accumulator);
Optional<T> reduce(BinaryOperator<T> accumulator);
<U> U reduce(U identity,
BiFunction<U, ? super T, U> accumulator,
BinaryOperator<U> combiner);
- 示例:将集合中的元素累加。 ```java String result = list.stream().reduce(“”, (s1, s2) -> s1 + s2); // JavaSpringMysqlPythonC++
Optional
<a name="XqAPT"></a>
### collect
【终止操作】将 Stream 流转换为其他形式,该操作主要作为进行中间操作后的可变规约操作。
1. 定义:
```java
<R> R collect(Supplier<R> supplier,
BiConsumer<R, ? super T> accumulator,
BiConsumer<R, R> combiner);
<R, A> R collect(Collector<? super T, A, R> collector);
- 示例1:将 List 转成 Set 。 ```java list.stream().collect(Collectors.toSet());
// 连接字符串 // String result = list.stream().collect(Collectors.joining(“-“));
3. 示例2:将 List 转成 Map。
groupingBy 会将 List 中的数据按指定属性分组,规约后 Map 的 key 为指定的属性类型,value 为 key 分组下的所有数据集合。<br />示例2中则会按照 code 分组,code 相同的数据在一个 map 哈希表中
```java
// score(BigDecimal) name(String) code(String)
Student student1 = new Student(new BigDecimal(200), "zhangsan", "1");
Student student2 = new Student(new BigDecimal(220), "zhangsan", "1");
Student student3 = new Student(new BigDecimal(500), "yangtao", "2");
Student student4 = new Student(new BigDecimal(504), "yangtao", "2");
Map<String, List<Object>> collect = list.stream()
.collect(Collectors.groupingBy(Student::getCode));
//{1=[Student{score=200, username='zhangsan', code='1'}, Student{score=220, username='zhangsan', code='1'}],
// 2=[Student{score=500, username='yangtao', code='2'}, Student{score=504, username='yangtao', code='2'}]}
查找与匹配
anyMatch
【短路终止操作】如果流的任何元素与提供的 断言 匹配,则为 true ,否则为 false。
定义:
boolean anyMatch(Predicate<? super T> predicate);
示例:判断集合中是否存在有长度大于 6 的元素。
boolean result = list.stream().anyMatch(s -> s.length() > 6) // false
allMatch
【短路终止操作】Stream 流中所有元素都与提供的 断言匹配,则为 ture,否则为 false。
定义:
boolean allMatch(Predicate<? super T> predicate);
示例:判断集合中的元素长度是否都小于等于 6。
boolean result = list.stream().allMatch(s -> s.length() <= 6); // true
noneMatch
【短路终止操作】Stream 流中的所有元素都与提供的 断言 不匹配,则返回 true,否则为 false。
定义:
boolean noneMatch(Predicate<? super T> predicate);
示例:判断集合中的元素长度是否都不满足大于 6。
boolean result = list.stream().noneMatch(s -> s.length() > 6); // true
findFirst
【短路终止操作】返回 Stream 流中第一个元素。
定义:
Optional<T> findFirst();
示例:
Optional<String> first = list.stream().findFirst(); String result = first.get(); // Java
findAny
【短路终止操作】返回 Stream 流中第一个元素。
- 此操作的行为明显是不确定的; 可以自由选择流中的任何元素。
- 这是为了在并行操作中实现最大性能;
- 代价是对同一源的多次调用可能不会返回相同的结果。 (如果需要稳定的结果,请改用findFirst() 。)
定义:
Optional<T> findAny();
示例: ```java Optional
first = list.stream().findAny(); String result = first.get(); // Java
Optional