> ## 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.

# StreamAPI终端操作
- URL: https://lucent.blog/streamapizhong-duan-cao-zuo/
- Published: 2020-06-25T10:11:27.000Z
- Updated: 2026-08-21T00:49:56.000Z
- Author: Lucent
- Tags: java, Stream API

Java Stream管道流是用于简化集合类元素处理的java API。  
在使用的过程中分为三个阶段：

- 将集合、数组、或行文本文件转换为java Stream管道流
- 管道流式数据处理操作，处理管道中的每一个元素。上一个管道中的输出元素作为下一个管道的输入元素。
- 管道流结果处理操作

回顾一下之前写过的一个例子：

```
List<String> nameStrs = Arrays.asList("Monkey", "Lion", "Giraffe","Lemur");

List<String> list = nameStrs.stream()
        .filter(s -> s.startsWith("L"))
        .map(String::toUpperCase)
        .sorted()
        .collect(toList());
System.out.println(list);

```

- 首先使用stream()方法将字符串List转换为管道流Stream
- 然后进行管道数据处理操作，先用fliter函数过滤所有大写L开头的字符串，然后将管道中的字符串转换为大写字母toUpperCase，然后调用sorted方法排序。这些API的用法在本号之前的文章有介绍过。其中还使用到了lambda表达式和函数引用。
- 最后使用collect函数进行结果处理，将java Stream管道流转换为List。最终list的输出结果是:`[LEMUR, LION]`

### ForEach和ForEachOrdered

如果我们只是希望将Stream管道流的处理结果打印出来，而不是进行类型转换，我们就可以使用forEach()方法或forEachOrdered()方法：

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

```

- parallel()函数表示对管道中的元素进行并行处理，而不是串行处理，这样处理速度更快。但是这样就有可能导致管道流中后面的元素先处理，前面的元素后处理，也就是元素的顺序无法保证
- forEachOrdered从名字上看就可以理解，虽然在数据处理顺序上可能无法保障，但是forEachOrdered方法可以在元素输出的顺序上保证与元素进入管道流的顺序一致。也就是下面的样子（forEach方法则无法保证这个顺序）：

```
Monkey
Lion
Giraffe
Lemur
Lion

```

### 元素的收集collect

java Stream 最常见的用法就是：一将集合类转换成管道流，二对管道流数据处理，三将管道流处理结果在转换成集合类。那么collect()方法就为我们提供了这样的功能：将管道流处理结果在转换成集合类。

#### 转换为Set

```
Set<String> collectToSet = Stream.of(
   "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
) 
.collect(Collectors.toSet());

```

- 最终collectToSet 中的元素是:`[Monkey, Lion, Giraffe, Lemur]`，因为Set会去重。

#### 转换为List

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

```

#### 通用的转换方式

上面的元素转换方式都是专用的。比如使用Collectors.toSet()收集为Set类型集合；使用Collectors.toList()收集为List类型集合。那么，有没有一种比较通用的数据元素收集方式，将数据收集为任意的Collection接口子类型。  
所以，这里介绍一种通用的元素收集方式，你可以将数据元素收集到任意的Collection类型：即向所需Collection类型提供构造函数的方式。

例如：

```
LinkedList<String> collectToCollection = Stream.of(
   "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
).collect(Collectors.toCollection(LinkedList::new));

```

- 最终collectToCollection中的元素是: `[Monkey, Lion, Giraffe, Lemur, Lion]`

#### 转换为Array

通过toArray(String\[\]::new)方法收集Stream的处理结果，将所有元素收集到字符串数组中。

```
String[] toArray = Stream.of(
   "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
) .toArray(String[]::new);

```

#### 转换为Map

使用Collectors.toMap()方法将数据元素收集到Map里面，但是出现一个问题：那就是管道中的元素是作为key，还是作为value。我们用到了一个Function.identity()方法，该方法很简单就是返回一个“ t -> t ”（输入就是输出的lambda表达式）。另外使用管道流处理函数`distinct()`来确保Map键值的唯一性。

```
Map<String, Integer> toMap = Stream.of(
    "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
)
.distinct()
.collect(Collectors.toMap(
       Function.identity(),   //元素输入就是输出，作为key
       s -> (int) s.chars().distinct().count()// 输入元素的不同的字母个数，作为value
));

// 最终toMap的结果是: {Monkey=6, Lion=4, Lemur=5, Giraffe=6}  

```

#### 分组转换groupingBy

Collectors.groupingBy用来实现元素的分组收集，下面的代码演示如何根据首字母将不同的数据元素收集到不同的List，并封装为Map。

```
Map<Character, List<String>> groupingByList =  Stream.of(
    "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
)
.collect(Collectors.groupingBy(
       s -> s.charAt(0) ,  //根据元素首字母分组，相同的在一组
       // counting()        // 加上这一行代码可以实现分组统计
));

// 最终groupingByList内的元素: {G=[Giraffe], L=[Lion, Lemur, Lion], M=[Monkey]}
//如果加上counting() ，结果是:  {G=1, L=3, M=1}

```

这是该过程的说明：**groupingBy第一个参数作为分组条件，第二个参数是子收集器。**

### 其他常用方法

```
boolean containsTwo = IntStream.of(1, 2, 3).anyMatch(i -> i == 2);
// 判断管道中是否包含2，结果是: true

long nrOfAnimals = Stream.of(
    "Monkey", "Lion", "Giraffe", "Lemur"
).count();
// 管道中元素数据总计结果nrOfAnimals: 4

int sum = IntStream.of(1, 2, 3).sum();
// 管道中元素数据累加结果sum: 6

OptionalDouble average = IntStream.of(1, 2, 3).average();
//管道中元素数据平均值average: OptionalDouble[2.0]

int max = IntStream.of(1, 2, 3).max().orElse(0);
//管道中元素数据最大值max: 3

IntSummaryStatistics statistics = IntStream.of(1, 2, 3).summaryStatistics();
// 全面的统计结果statistics: IntSummaryStatistics{count=3, sum=6, min=1, average=2.000000, max=3}

```