Stream 流是简化集合和数组操作的一种编程方式,使得集合和数组的操作像水流一样流畅。

下面通过 原理 + 实战 的方式了解 Stream 的用法。

获取方式

  1. 集合:default Stream stream();
  2. 数组:
    1. Arrays.stream(T[] array);
    2. Stream.of(T… values); (可变参数可以接收数组作为参数) ```java // 1. 集合 Collection list = new ArrayList<>(); Stream ss = list.stream();

// 2. 数组 String[] arrs = new String[]{“Java”, “Python” ,”C”}; Stream arrs1 = Arrays.stream(arrs); Stream arrs2 = Stream.of(arrs);

  1. <a name="rwfWZ"></a>
  2. # Stream 操作分类
  3. 1. 中间操作(intermediate):通过一系列中间(Intermediate)方法,对数据集进行过滤、检索等数据集的再次处理。
  4. 1. 中间操作的特点是方法返回值还是 Stream 类型,可以继续链式调用其他方法执行操作。
  5. 1. 中间操作是对数据的加工,注意,中间操作是 lazy 操作,并不会立马启动,需要等待终止操作才会执行。
  6. 2. 终止操作(Terminal):通过最终(terminal)方法完成对数据集中元素的处理。
  7. 1. 终止操作的特点是方法返回值为 空 或者 一个其他类型的结果。
  8. 1. 终止操作是 Stream 的启动操作,**只有加上终止操作,Stream才会真正的开始执行**。
  9. - 无状态(Stateless):指元素的处理不受之前元素的影响;
  10. - 有状态(Stateful):指该操作只有拿到所有元素之后才能继续下去。
  11. - 非短路操作(Unshort-circuiting):指必须处理所有元素才能得到最终结果;
  12. - 短路操作(Short-circuiting):指遇到某些符合条件的元素就可以得到最终结果,如 A || B,只要A为true,则无需判断B的结果。
  13. ![](https://cdn.nlark.com/yuque/0/2021/jpeg/12568777/1623808494277-f6acce55-4e76-41d8-809f-2184936f72a1.jpeg)
  14. <a name="vVBCV"></a>
  15. ## 测试集合
  16. Stream 中间操作不会自己启动,所以测试中都会加上 forEach 终止操作来启动 Stream 流的执行。
  17. ```java
  18. List<String> list = Arrays.asList("Java", "", "Spring", "Mysql", "Python", "", "C++");

中间操作

filter

【中间操作】过滤元素,筛选 Stream 流中符合条件的元素,作为流返回。

  1. 定义:

    Stream<T> filter(Predicate<? super T> predicate);
    
  2. 示例:找出集合中的空元素

    list.stream().filter(String::isEmpty).forEach(System.out::println);
    

    map

    【中间操作】对 Stream 流中的元素执行指定操作后映射为新的值流返回(会改变之前的集合元素),相当于加工。

  3. 定义:

    <R> Stream<R> map(Function<? super T, ? extends R> mapper);
    
  4. 示例:将集合中的元素变为大写

    list.stream().map(String::toUpperCase).forEach(System.out::println);
    

    peek

    【中间操作】返回一个由该流的元素组成的流,另外在每个元素上执行提供的操作,因为元素从结果流中被消耗。(Consumer 没有返回值,不会改变原来 Stream 流中的值)

  5. 定义:

    Stream<T> peek(Consumer<? super T> action);
    
  6. 示例:源码中的说明

    @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 个 元素。

  1. 定义:

    Stream<T> limit(long maxSize);
    
  2. 示例:取集合中前 4 个元素。

    list.stream().limit(4).forEach(System.out::println);
    

    skip

    【有状态中间操作】在丢弃流的前 n 元素后,返回由该流的其余元素组成的流。 如果此流包含少于 n 元素,则将返回一个空流。

  3. 定义:

    Stream<T> skip(long n);
    
  4. 示例:跳过集合中前 4 个元素。

    list.stream().skip(4).forEach(System.out::println);
    

    distinct

    【有状态中间操作】返回由该流的不同元素(根据Object.equals(Object) )组成的流。

  • 对于有序流,不同元素的选择是稳定的(对于重复元素,保留遇到顺序中最先出现的元素。)
  • 对于无序流,没有稳定性保证。
  1. 定义:

    Stream<T> distinct();
    
  2. 示例:去除集合中重复的元素。

    list.stream().distinct().forEach(System.out::println);
    

    sorted

    【有状态中间操作】返回由该流的元素组成的流,按自然顺序排序。

  • 如果此流的元素不是 Comparable ,则在执行终端操作时可能会抛出java.lang.ClassCastException 。
  • 对于有序流,排序是稳定的。 对于无序流,没有稳定性保证。
  1. 定义: ```java Stream sorted();

Stream sorted(Comparator<? super T> comparator);


2. 示例:按照 自然排序/自然排序倒序 集合中的元素。
```java
list.stream().sorted().forEach(System.out::println);

// 还可以实现 Comparator 接口来自定义排序规则
list.stream().sorted(Comparator.reverseOrder()).forEach(System.out::println);

终止操作

forEach

【终止操作】遍历操作,依次遍历 Stream 流中的元素,并执行给定的行为。

  1. 定义:

    void forEach(Consumer<? super T> action);
    
  2. 示例:遍历集合中的元素 ```java list.stream().forEach(System.out::println);

// 集合只遍历可简写为 Collection 自带的 forEach() 方法 // list.forEach(System.out::println);

<a name="zOYe5"></a>
### toArray
【终止操作】返回一个包含此流元素的数组。

1. 定义:
```java
Object[] toArray();
  1. 示例:将集合转成数组。 ```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);
  1. 示例:返回集合中最小/最大的元素 ```java Optional min = list.stream().min(Comparator.naturalOrder()); System.out.println(min.get());

Optional max = list.stream().max(Comparator.naturalOrder()); System.out.println(max.get());

<a name="jMNfr"></a>
### count
【终止操作】返回此流中元素的计数。

1. 定义:
```java
long count();
  1. 示例:统计集合中的元素个数 ```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);
  1. 示例:将集合中的元素累加。 ```java String result = list.stream().reduce(“”, (s1, s2) -> s1 + s2); // JavaSpringMysqlPythonC++

Optional result = list.stream().reduce((s1, s2) -> s1 + s2);

<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. 示例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。

  1. 定义:

    boolean anyMatch(Predicate<? super T> predicate);
    
  2. 示例:判断集合中是否存在有长度大于 6 的元素。

    boolean result = list.stream().anyMatch(s -> s.length() > 6) // false
    

    allMatch

    【短路终止操作】Stream 流中所有元素都与提供的 断言匹配,则为 ture,否则为 false。

  3. 定义:

    boolean allMatch(Predicate<? super T> predicate);
    
  4. 示例:判断集合中的元素长度是否都小于等于 6。

    boolean result = list.stream().allMatch(s -> s.length() <= 6); // true
    

    noneMatch

    【短路终止操作】Stream 流中的所有元素都与提供的 断言 不匹配,则返回 true,否则为 false。

  5. 定义:

    boolean noneMatch(Predicate<? super T> predicate);
    
  6. 示例:判断集合中的元素长度是否都不满足大于 6。

    boolean result = list.stream().noneMatch(s -> s.length() > 6); // true
    

    findFirst

    【短路终止操作】返回 Stream 流中第一个元素。

  7. 定义:

    Optional<T> findFirst();
    
  8. 示例:

    Optional<String> first = list.stream().findFirst();
    String result = first.get(); // Java
    

    findAny

    【短路终止操作】返回 Stream 流中第一个元素。

  • 此操作的行为明显是不确定的; 可以自由选择流中的任何元素。
  • 这是为了在并行操作中实现最大性能;
  • 代价是对同一源的多次调用可能不会返回相同的结果。 (如果需要稳定的结果,请改用findFirst() 。)
  1. 定义:

    Optional<T> findAny();
    
  2. 示例: ```java Optional first = list.stream().findAny(); String result = first.get(); // Java

Optional first = list.parallelStream().findAny(); String result = first.get(); // Python ```