> ## Content Index
> Fetch the complete content index at: https://lucent.blog/llms.txt
> Use this file to discover other available public pages before exploring further.

# Stream的状态与并行操作
- URL: https://lucent.blog/streamde-zhuang-tai-yu-bing-xing-cao-zuo/
- Published: 2020-06-25T02:39:34.000Z
- Updated: 2026-08-21T00:49:55.000Z
- Author: Lucent
- Tags: java, Stream API

### 有状态与无状态

在编程中，经常会接触到“有状态”，“无状态”，绝大部分的人都比较蒙。而且在不同的场景下，“状态”这个词的含义似乎有所不同。

- 状态通常代表公用数据，有状态就是有“公用数据”
- 因为有公用的数据，状态通常需要额外的存储。
- 状态通常被多人、多用户、多线程、多次操作，这就涉及到状态的管理及变更操作。

#### 举个例子：

- web开发session就是一种状态，访问者的多次请求关联同一个session，这个session需要存储到内存或者redis。多次请求使用同一个公用的session，这个session就是状态数据。
- vue的vuex的store就是一种状态，首先它是多组件公用的，其次是不同的组件都可以修改它，最后它需要独立于组件单独存储。所以store就是一种状态。
- filter与map操作，不需要管道流的前面后面元素相关，所以不需要额外的记录元素之间的关系。输入一个元素，获得一个结果。
- sorted是排序操作、distinct是去重操作。像这种操作都是和别的元素相关的操作，我自己无法完成整体操作。就像班级点名就是无状态的，喊到你你就答到就可以了。如果是班级同学按大小个排序，那就不是你自己的事了，你得和周围的同学比一下身高并记住，你记住的这个身高比较结果就是一种“状态”。所以这种操作就是有状态操作。

### Limit与Skip管道数据截取

```
List<String> limitN = Stream.of("Monkey", "Lion", "Giraffe", "Lemur")
        .limit(2)
        .collect(Collectors.toList());
List<String> skipN = Stream.of("Monkey", "Lion", "Giraffe", "Lemur")
        .skip(2)
        .collect(Collectors.toList());

```

- limt方法传入一个整数n，用于截取管道中的前n个元素。经过管道处理之后的数据是：\[Monkey, Lion\]。
- skip方法与limit方法的使用相反，用于跳过前n个元素，截取从n到末尾的元素。经过管道处理之后的数据是： \[Giraffe, Lemur\]

### Distinct元素去重

```
List<String> uniqueAnimals = Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion")
        .distinct()
        .collect(Collectors.toList());

```

结果：

```
 ["Monkey", "Lion", "Giraffe", "Lemur"]

```

### Sorted排序

默认的情况下，sorted是按照字母的自然顺序进行排序。

```
List<String> alphabeticOrder = Stream.of("Monkey", "Lion", "Giraffe", "Lemur")
        .sorted()
        .collect(Collectors.toList());

```

### 串行、并行与顺序

通常情况下，有状态和无状态操作不需要我们去关心。除非你使用了并行操作。

- 串行的好处是可以保证顺序，但是通常情况下处理速度慢一些
- 并行的好处是对于元素的处理速度快一些（通常情况下），但是顺序无法保证。这可能会导致进行一些有状态操作的时候，最后得到的不是你想要的结果。  
例如：

```
Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion")
        .parallel()
        .forEach(System.out::println);

```

parallel()函数表示对管道中的元素进行并行处理，而不是串行处理。但是这样就有可能导致管道流中后面的元素先处理，前面的元素后处理，也就是元素的顺序无法保证。  
第一次运行结果：

```
Giraffe
Lion
Lion
Monkey
Lemur

```

第二次运行结果：

```
Giraffe
Lion
Lemur
Lion
Monkey

```

通常情况下，parallel()能够很好的利用CPU的多核处理器，达到更好的执行效率和性能，建议使用。但是有些特殊的情况下，parallel并不适合。

- 从处理性能的角度，parallel()更适合处理ArrayList，而不是LinkedList。因为ArrayList从数据结构上讲是基于数组的，可以根据索引很容易的拆分为多个。
- 适用于无状态操作：每个元素的计算都不得依赖或影响任何其他元素的计算，的运算场景。
- 从文本文件里面边读边处理的场景，不适合parallel()并行处理。parallel()一开始就容量固定的集合，这样能够平均的拆分、同步处理。

### Stream管道流操作

![78f74991175f6ddc5c27fff109f0fc66_942x578.png](https://img-1251540275.cos.ap-shanghai.myqcloud.com/blog/78f74991175f6ddc5c27fff109f0fc66_942x578_1593052763065.png)