0%

stream集合操作符笔记

前言

用了这么久的jdk8 的stream集合
感觉还是很吊的 特别是作统计计算、集合转化之类的操作

虽然有parallelStream 来进行并行计算 但是 不推荐这么去使用 原因如下
虽然有并行 但是 parallelStream 的并行数量是按照jvm的核心数量去启动的 这个时候就有点蛋疼了 如果真的需要并行 还是建议使用 threadPool去执行 而不是简单的使用 parallelStream
parallelStream 只是把任务并行了 但是该有的竞争状态 还是有 就是说和你使用线程池是差不多的也是要考虑竞争状态的问题

常用操作符列表

名称 表达式 作用 备注
filter t->boolean 过滤数 据
map t->r 处理数据 为每一个数据作map中的操作
flatMap t->r.stream() 处理数据并且扁平化 为每个数据进行处理 并且会返回一个Stream 处理List> 这种数据的时候可以通过此操作扁平化内部的那个list
distinct - 去重并且返回一个新的stream 进行数据去重的时候使用 必须是有限的stream
sorted - 排序并且返回一个新的stream 进行stream排序使用 但是这个必须要是有限的stream
peek t->void 预览、执行某个不返回的操作 每次返回新的stream 避免消耗stream 做一些void的操作使用
limit - 截断数据 截断前x个数据 返回新的stream
skip - 跳过数据 跳过前x个数据 返回新的stream
forEach t->void 迭代数据 内部迭代 每啥好说的
reduce (identity,(x,y)->result)、((x,y)->result) 计数器 做一些复杂的综合统计适合
collect (void->t,r->void,r->void)、(collector) 收集结果 将结果收集返回给其他对象
min (o1,o2)->o1 or o2 获取最小的元素 必须是有限的元素
max (o1,o2)->o1 or o2 获取最大的元素 必须是有限的元素
count - 统计数量 统计数量
anyMatch t->boolean 匹配 只要有一个匹配就返回true
allMatch t->boolean 匹配 必须所有元素匹配才返回true
noneMatch t->boolean 匹配 必须所有元素不匹配返回true
findFirst - 获取第一个元素 获取到第一个元素马上返回
findAny - 获取返回的元素

案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
package com.ming;

import org.junit.Test;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
* 测试 stream 用法
*
* @author ming
* @date 2018-06-26 15:45:08
*/
public class TestStream {


/**
* 将List<T1> 转换成 Map<id,T1>
*
* @author ming
* @date 2018-06-26 15:54:54
*/
@Test
public void listToMap() {
List<T1> list = new ArrayList<>();
for (int i = 0; i < 3; i++) {
list.add(new T1("id" + i, "name" + i));
}
//转换成 id 为key T1为value的map
Map<String, T1> map = list.stream().collect(Collectors.toMap(T1::getId, t -> t));
System.out.println(map);
//当出现重复值 按照 (oV, nV) -> nV 来选择新的value
Map<String, T1> map1 = list.stream().collect(Collectors.toMap(T1::getId, t -> t, (oV, nV) -> nV));
System.out.println(map1);
}


/**
* 获取List<T2> 中的t1的list的合集
*
* @author ming
* @date 2018-06-26 16:02:35
*/
@Test
public void ListToFlatList() {
List<T2> list = new ArrayList<>();
for (int i = 0; i < 3; i++) {
List<T1> t1List = new ArrayList<>();
for (int j = 0; j < 3; j++) {
t1List.add(new T1("id" + i, "name" + i));
}
list.add(new T2("id" + i, "name" + i, t1List));
}
List<T1> resultList = list.stream().flatMap(f -> f.getT1List().stream()).collect(Collectors.toList());
System.out.println(resultList);
}

/**
* 将 List<T3>中的num进行累加计数
*
* @author ming
* @date 2018-06-26 16:06:24
*/
@Test
public void numReduce() {
List<T3> list = new ArrayList<>();
for (int i = 0; i < 3; i++) {
list.add(new T3("id" + i, i));
}
Integer countNum = list.stream().map(T3::getNum).reduce(0, (sum, item) -> sum + item);
System.out.println(countNum);
Integer countNum1 = list.stream().map(T3::getNum).reduce(0, Integer::sum);
System.out.println(countNum1);
}


/**
* 将List<T4>按照id 分组并且 累加price
* 分两种方案
* 一是先分组 然后map->reduce
* 二直接分组 进行reduce 取巧进行对象的累加
*
* @author ming
* @date 2018-07-05 09:58:01
*/
@Test
public void testGroupByAndReduce() {
List<T4> list = new ArrayList<>();
list.add(new T4(1, BigDecimal.valueOf(1)));
list.add(new T4(1, BigDecimal.valueOf(10)));
list.add(new T4(2, BigDecimal.valueOf(1)));
list.add(new T4(2, BigDecimal.valueOf(10)));
/*

//方案一 先分组 然后迭代处理
Map<Integer, BigDecimal> result = new HashMap<>();
list.stream().collect(Collectors.groupingBy(T4::getId, Collectors.toSet()))
.forEach((k, v) -> {
result.put(k, v.stream().map(T4::getPrice).reduce(BigDecimal.ZERO, BigDecimal::add));
});
System.out.println(result);
*/

/*

//方案二 使用取巧的方案 进行对象累加 这样 分组id不变 而且内部的属性也可以按照自己的定义去计算
Map<Integer, T4> result = list.stream()
.collect(Collectors.groupingBy(T4::getId
, Collectors.reducing(new T4(1, BigDecimal.ZERO), (o, item) -> new T4(o.getId(), o.getPrice().add(item.getPrice())))));
System.out.println(result);
*/
}

}

class T1 {
private String id;
private String name;


public T1() {
}

public T1(String id, String name) {
this.id = id;
this.name = name;
}

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}

class T2 {
private String id;
private String name;
private List<T1> t1List;

public T2() {
}

public T2(String id, String name, List<T1> t1List) {
this.id = id;
this.name = name;
this.t1List = t1List;
}

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public List<T1> getT1List() {
return t1List;
}

public void setT1List(List<T1> t1List) {
this.t1List = t1List;
}
}

class T3 {
private String id;
private Integer num;


public T3() {
}

public T3(String id, Integer num) {
this.id = id;
this.num = num;
}

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public Integer getNum() {
return num;
}

public void setNum(Integer num) {
this.num = num;
}
}


class T4 {
private Integer id;
private BigDecimal price;

public T4() {
}

public T4(Integer id, BigDecimal price) {
this.id = id;
this.price = price;
}

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public BigDecimal getPrice() {
return price;
}

public void setPrice(BigDecimal price) {
this.price = price;
}

@Override
public String toString() {
return "T4{" +
"id=" + id +
", price=" + price +
'}';
}
}

总结

jdk8 出了很多实用的功能 这个stream只是其中之一 算是常用的 在大多数 集合转换、数据计算类型的操作中 用stream 操作会节省很多代码 而且看起来容易理解 并且性能还稍高一点