1 package stream;
2
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.Collection;
6 import java.util.Comparator;
7 import java.util.HashMap;
8 import java.util.HashSet;
9 import java.util.IdentityHashMap;
10 import java.util.Iterator;
11 import java.util.LinkedHashMap;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.Map.Entry;
15 import java.util.Random;
16 import java.util.Set;
17 import java.util.StringJoiner;
18 import java.util.function.Function;
19 import java.util.stream.Collectors;
20 import java.util.stream.IntStream;
21 import java.util.stream.Stream;
22 import java.util.stream.StreamSupport;
23
24 public class Test10 {
25
26 static List<Integer> numbers = Arrays.asList(1, 5, 3, 2, 4);
27
28 static List<String> strs = Arrays.asList("b2", "b1", "a2", "c", "b", "a");
29
30 static List<List<String>> strsList = Arrays.asList(strs);
31
32 static Person p1 = new Person(GenderEnum.MALE, 20, "Jack");
33 static Person p2 = new Person(GenderEnum.FEMALE, 20, "Lily");
34 static Person p3 = new Person(GenderEnum.MALE, 10, "John");
35 static Person p4 = new Person(GenderEnum.FEMALE, 10, "Lucy");
36 static Person p5 = new Person(GenderEnum.MALE, 20, "Eason");
37
38 static List<Person> persons = Arrays.asList(p1, p2, p3, p4, p5);
39
40 static void method1() {
41 // 常用數據結構轉流的方式
42
43 // Collection接口 提供了stream()方法
44
45 // 1. List轉流
46 List<String> list = new ArrayList<>();
47 Stream<String> streamA = list.stream();
48
49 // ------------------------------------------------------------
50
51 // 2. Set轉流
52 Set<String> set = new HashSet<>();
53 Stream<String> streamB = set.stream();
54
55 // ------------------------------------------------------------
56
57 // 3. Map轉流
58 Map<String, Integer> map = new HashMap<>();
59 Stream<Entry<String, Integer>> streamC = map.entrySet().stream();
60 Stream<Integer> streamD = map.values().stream();
61
62 // ------------------------------------------------------------
63
64 // 4. 數組轉流
65 String[] arr = { "A", "B", "C" };
66 Arrays.stream(arr);
67
68 // ------------------------------------------------------------
69
70 // 5. Iterable轉流
71 Iterable<String> iterable = new ArrayList<>();
72 StreamSupport.stream(iterable.spliterator(), false);
73 }
74
75 static void method2() {
76 // 流的拼接
77
78 List<String> listA = Arrays.asList("s1", "s2", "s3");
79 List<String> listB = Arrays.asList("t1", "t2", "t3");
80
81 // Stream.concat()實現多個流拼接
82 Stream<String> streamA = Stream.concat(listA.stream(), listB.stream());
83
84 // Stream.of()實現拼接
85 // 多個元素
86 Stream<String> streamB = Stream.of("A", "B", "C");
87 // 多個List
88 Stream<String> streamC = Stream.of(listA, listB).flatMap(Collection::stream);
89 // 多個Stream
90 Stream<String> streamD = Stream.of(listA.stream(), listB.stream()).flatMap(Function.identity());
91
92 // flatMap實現子元素拼接
93 List<Item> items = new ArrayList<>();
94 Stream<String> streamE = items.stream().flatMap(i -> i.getSubItems().stream());
95 Stream<String> streamF = items.stream().map(Item::getSubItems).flatMap(Collection::stream);
96 }
97
98 static void method3() {
99 // 高級收集器
100
101 // 1. 字符串拼接
102
103 List<String> strs = Arrays.asList("s1", "s2", "s3");
104
105 // 無分隔符
106 String str1 = strs.stream().collect(Collectors.joining());
107 // 單個分隔符
108 String str2 = strs.stream().collect(Collectors.joining(","));
109 // 前后綴及分隔符
110 String str3 = strs.stream().collect(Collectors.joining(",", "[", "]"));
111
112 // ----------------------------------------------------------------------------------------------------
113
114 // 返回集合
115
116 // 2. 返回數組
117
118 // Object數據(無參默認)
119 Object[] arr1 = strs.stream().toArray();
120 // 特定類型數據
121 String[] arr2 = strs.stream().toArray(String[]::new);
122 // 數組指定長度
123 String ids = "1, 2, 3, 4";
124 String[] arr3 = Arrays.asList(ids.split(",")).stream().map(String::trim).toArray(size -> new String[size]);
125
126 // ----------------------------------------------------------------------------------------------------
127
128 // 3. 返回List
129 // 默認List
130 List<String> list1 = strs.stream().filter(str -> str.length() > 5).map(String::toUpperCase).collect(Collectors.toList());
131 // 返回特定類型如ArrayList
132 List<String> list2 = strs.stream().filter(str -> str.length() > 5).map(String::toUpperCase).collect(Collectors.toCollection(ArrayList::new));
133
134 // ----------------------------------------------------------------------------------------------------
135
136 // 4. 返回Map
137
138 // List轉Map
139 List<Item> items = Arrays.asList(new Item("0001", "name"), new Item("0002", "name2"));
140 // 成員作為value
141 Map<String, String> map1 = items.stream().collect(Collectors.toMap(Item::getItemId, Item::getName));
142 // 元素作為value
143 Map<String, Item> map2 = items.stream().collect(Collectors.toMap(Item::getItemId, Function.identity()));
144 // value重復取第一個
145 Map<String, Item> map3 = items.stream().collect(Collectors.toMap(Item::getItemId, Function.identity(), (n1, n2) -> n1));
146 // value重復自定義異常,指定返回類型
147 Map<String, Item> map4 = items.stream()
148 .collect(Collectors.toMap(Item::getItemId, Function.identity(), (a, b) -> {
149 throw new IllegalStateException("cannot add duplicate key: " + a);
150 }, IdentityHashMap::new));
151
152 // Map轉Map
153 Map<String, Integer> map = new HashMap<>();
154 Map<String, Integer> map_ = map.entrySet().stream().filter(e -> e.getValue() > 10).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
155 }
156
157 static void method4() {
158 // 排序 sorted
159
160 // 數字排序
161
162 List<Integer> numbers = Arrays.asList(1, 5, 3, 2, 4);
163
164 // 1. 升序(默認)
165 numbers.stream().sorted();
166 // 1, 2, 3, 4, 5
167
168 // 2. 降序
169 numbers.stream().sorted(Comparator.reverseOrder());
170 // 5, 4, 3, 2, 1
171
172 // --------------------------------------------------------------------------------
173
174 // 字符排序
175
176 List<String> strs = Arrays.asList("b2", "b1", "a2", "c", "b", "a");
177
178 // 1. 默認
179 List<String> strSorted1 = strs.stream().sorted().collect(Collectors.toList());
180 // a, a2, b, b1, b2, c
181
182 // 2. 自定義:先比較長度
183 strs.stream().sorted((s1, s2) -> s1.length() - s2.length());
184 List<String> strSorted2 = strs.stream()
185 .sorted(Comparator.comparing(String::length).thenComparing(Comparator.naturalOrder()))
186 .collect(Collectors.toList());
187 // a, b, c, a2, b1, b2
188
189 // --------------------------------------------------------------------------------
190
191 // 自定義類型排序
192
193
194 // 1. 可實現Comparable<T>接口
195 List<Person> pVal = persons.stream().sorted().collect(Collectors.toList());
196 /*
197 * Person [gender=MALE, age=10, name=John]
198 * Person [gender=MALE, age=20, name=Eason]
199 * Person [gender=MALE, age=20, name=Jack]
200 * Person [gender=FEMALE, age=10, name=Lucy]
201 * Person [gender=FEMALE, age=20, name=Lily]
202 *
203 */
204
205 // List可直接排序,傳入compareTo方法引用
206 List<Person> personsNew = new ArrayList<>(persons);
207 personsNew.sort(Person::compareTo);
208
209 // 2. 使用比較器鏈,排序方式更靈活
210 persons.sort(Comparator.comparing(Person::getAge).thenComparing(Person::getGender).thenComparing(Person::getName));
211 /*
212 * Person [gender=MALE, age=10, name=John]
213 * Person [gender=FEMALE, age=10, name=Lucy]
214 * Person [gender=MALE, age=20, name=Eason]
215 * Person [gender=MALE, age=20, name=Jack]
216 * Person [gender=FEMALE, age=20, name=Lily]
217 *
218 */
219 }
220
221 static void method5() {
222 // 分組與分區
223
224 // 分組
225 Map<GenderEnum, List<Person>> grouped1 = persons.stream().collect(Collectors.groupingBy(Person::getGender));
226 // 子分組,多個分組
227 Map<GenderEnum, Map<Integer, List<Person>>> grouped2 = persons.stream()
228 .collect(Collectors.groupingBy(Person::getGender, LinkedHashMap::new,
229 Collectors.groupingBy(Person::getAge, LinkedHashMap::new, Collectors.toList())));
230
231 // --------------------------------------------------------------------------------
232
233 // 分區
234 Map<Boolean, List<Person>> partitioned1 = persons.stream().collect(Collectors.partitioningBy(person -> person.getAge() <= 6));
235 // 分區並計數
236 Map<Boolean, Long> partitioned2 = persons.stream().collect(Collectors.partitioningBy(person -> person.getAge() <= 6, Collectors.counting()));
237 }
238
239 static <T> void method6() {
240 // 歸約 reduce
241
242 // 數字
243 Integer reduced1 = numbers.stream().reduce((x, y) -> x + y).get();
244 // 數字,指定初始值
245 Integer reduced2 = numbers.stream().reduce(0, (x, y) -> x + y);
246
247 // 字符串拼接
248 String reduced3 = strs.stream().reduce((s1, s2) -> s1 + s2).get();
249 // 字符串拼接,指定前綴
250 String reduced4 = strs.stream().reduce("prefix", (s1, s2) -> s1 + s2);
251
252 // --------------------------------------------------------------------------------
253
254 // 數字,求最小值
255 Integer min = numbers.stream().reduce(Math::min).get();
256 // 數字,求最大值
257 Integer max = numbers.stream().reduce(Math::max).get();
258 // 數字,求和
259 Integer sum = numbers.stream().reduce(Integer::sum).get();
260
261 // --------------------------------------------------------------------------------
262
263 // 實現流的拼接
264 Stream<String> reduced5 = strsList.stream().map(list -> list.stream()).reduce(Stream::concat).get();
265
266 Iterable<T>[] inputs = null;
267 Iterator<T> iterator = Stream.of(inputs).map(it -> StreamSupport.stream(it.spliterator(), false)).reduce(Stream::concat).orElseGet(Stream::empty).iterator();
268
269 }
270
271 static void method7() {
272 // findFirst 返回第一個符合條件
273 strs.stream().filter(str -> str.length() > 10).findFirst().get();
274 // findAny 返回任意一個符合條件,串行流和findFirst相同,並行流返回最先有值的線程
275 strs.stream().filter(str -> str.length() > 10).findAny().get();
276 // anyMatch 任意符合
277 boolean flag1 = strs.stream().anyMatch(str -> str.length() > 10);
278 // allMatch 全部符合
279 boolean flag2 = strs.stream().allMatch(str -> str.length() > 10);
280 // noneMatch 全不符合
281 boolean flag3 = strs.stream().noneMatch(str -> str.length() > 10);
282
283 // --------------------------------------------------------------------------------
284
285 // distinct 去重
286 strs.stream().distinct();
287 // count 計數
288 strs.stream().filter(str -> str.length() > 10).count();
289 // skip 跳過
290 strs.stream().filter(str -> str.length() > 10).skip(3);
291 // limit 限定數量
292 strs.stream().filter(str -> str.length() > 10).limit(3);
293
294 // --------------------------------------------------------------------------------
295
296 // 遍歷
297 strs.stream().forEach(System.out::println);
298
299 }
300
301 static void method8() {
302 // IntStream
303
304 // 使用IntStream生成50個連續字符
305
306 IntStream.range(0, 50).mapToObj(s -> "*").collect(Collectors.joining());
307 IntStream.range(0, 50).mapToObj(s -> "*").collect(Collectors.joining(""));
308 IntStream.rangeClosed(1, 50).mapToObj(s -> "*").reduce((s1, s2) -> s1 + s2).get();
309 IntStream.rangeClosed(1, 50).mapToObj(s -> "*").reduce(new StringJoiner("", "[", "]"), StringJoiner::add, StringJoiner::merge);
310
311 // 生成隨機數
312 Random random = new Random();
313 IntStream.generate(random::nextInt);
314
315 // 生成特定元素
316 IntStream.iterate(1, i -> i * 2);
317 }
318
319 static class Person implements Comparable<Person> {
320 private GenderEnum gender;
321 private int age;
322 private String name;
323
324 public Person(GenderEnum gender, int age, String name) {
325 this.gender = gender;
326 this.age = age;
327 this.name = name;
328 }
329
330 public GenderEnum getGender() {
331 return gender;
332 }
333
334 public void setGender(GenderEnum gender) {
335 this.gender = gender;
336 }
337
338 public int getAge() {
339 return age;
340 }
341
342 public void setAge(int age) {
343 this.age = age;
344 }
345
346 public String getName() {
347 return name;
348 }
349
350 public void setName(String name) {
351 this.name = name;
352 }
353
354 @Override
355 public int compareTo(Person o) {
356 if (this.gender != o.gender) {
357 return this.gender.compareTo(o.gender);
358 }
359 if (this.age != o.age) {
360 return this.age - o.age;
361 }
362
363 return this.name.compareTo(o.name);
364 }
365
366 @Override
367 public String toString() {
368 return "Person [gender=" + gender + ", age=" + age + ", name=" + name + "]";
369 }
370 }
371
372 enum GenderEnum {
373 MALE, FEMALE
374 }
375
376 static class Item {
377 private String itemId;
378 private String name;
379 private String value;
380 private List<String> subItems;
381
382 public Item(String itemId, String name) {
383 this.itemId = itemId;
384 this.name = name;
385 }
386
387 public String getItemId() {
388 return itemId;
389 }
390
391 public void setItemId(String itemId) {
392 this.itemId = itemId;
393 }
394
395 public String getName() {
396 return name;
397 }
398
399 public void setName(String name) {
400 this.name = name;
401 }
402
403 public String getValue() {
404 return value;
405 }
406
407 public void setValue(String value) {
408 this.value = value;
409 }
410
411 public List<String> getSubItems() {
412 return subItems;
413 }
414
415 public void setSubItems(List<String> subItems) {
416 this.subItems = subItems;
417 }
418
419 @Override
420 public String toString() {
421 return "Item [itemId=" + itemId + ", name=" + name + ", value=" + value + ", subItems=" + subItems + "]";
422 }
423 }
424
425 public static void main(String[] args) {
426 method5();
427 }
428 }