ZB-032-03Stream的Collector

Collector 操作

Collector 与 Collectors

Collectors API

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
*
* <pre>{@code
* // Accumulate names into a List
* List<String> list = people.stream().map(Person::getName).collect(Collectors.toList());
*
* // Accumulate names into a TreeSet
* Set<String> set = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));
*
* // Convert elements to strings and concatenate them, separated by commas
* String joined = things.stream()
* .map(Object::toString)
* .collect(Collectors.joining(", "));
*
* // Compute sum of salaries of employee
* int total = employees.stream()
* .collect(Collectors.summingInt(Employee::getSalary)));
*
* // Group employees by department
* Map<Department, List<Employee>> byDept
* = employees.stream()
* .collect(Collectors.groupingBy(Employee::getDepartment));
*
* // Compute sum of salaries by department
* Map<Department, Integer> totalByDept
* = employees.stream()
* .collect(Collectors.groupingBy(Employee::getDepartment,
* Collectors.summingInt(Employee::getSalary)));
*
* // Partition students into passing and failing
* Map<Boolean, List<Student>> passingFailing =
* students.stream()
* .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD));
*
* }</pre>
  • collector 操作是最强⼤的操作
  • toSet/toList/toCollection
  • joining()
  • toMap()
  • groupingBy()

把结果收集到 TreeSet

1
2
3
4
5
6
7
List<User> users = Arrays.asList(new User("张三",20),new User("张三疯",15),new User("李四",100));

TreeSet<String> result = users.stream().filter(user->user.name.startsWith("张"))
.sorted(Comparator.comparing(User::getAge))
.map(User::getName)
// 重点就是 这句
.collect(Collectors.toCollection(TreeSet::new));

Collectors.groupingBy 将User 按照部门分组

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
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Arrays;
import java.util.stream.Collectors;

public class Problem4 {
// 再用流的方法把之前的题目做一遍吧:
// 请编写一个方法,对传入的List<Employee>进行如下处理:
// 返回一个从部门名到这个部门的所有用户的映射。同一个部门的用户按照年龄进行从小到大排序。
// 例如,传入的employees是[{name=张三, department=技术部, age=40 }, {name=李四, department=技术部, age=30 },
// {name=王五, department=市场部, age=40 }]
// 返回如下映射:
// 技术部 -> [{name=李四, department=技术部, age=30 }, {name=张三, department=技术部, age=40 }]
// 市场部 -> [{name=王五, department=市场部, age=40 }]
public static Map<String, List<Employee>> collect(List<Employee> employees) {
return employees.stream()
.sorted(Comparator.comparing(Employee::getAge))
.collect(Collectors.groupingBy(Employee::getDepartment));
}

public static void main(String[] args) {
System.out.println(
collect(
Arrays.asList(
new Employee(1, "张三", 40, "技术部"),
new Employee(2, "李四", 30, "技术部"),
new Employee(3, "王五", 40, "市场部"))));
}

static class Employee {
// 用户的id
private final Integer id;
// 用户的姓名
private final String name;
// 用户的年龄
private final int age;
// 用户的部门,例如"技术部"/"市场部"
private final String department;

Employee(Integer id, String name, int age, String department) {
this.id = id;
this.name = name;
this.age = age;
this.department = department;
}

public Integer getId() {
return id;
}

public String getName() {
return name;
}

public int getAge() {
return age;
}

public String getDepartment() {
return department;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Employee person = (Employee) o;
return Objects.equals(id, person.id);
}

@Override
public int hashCode() {
return Objects.hash(id);
}

@Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", department='" + department + '\'' +
'}';
}
}
}

Collectors.joining把流中元素以 “,” 连接为一个 字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.stream.Collectors;

public class Problem6 {
// 使用流的方法,把所有长度等于1的单词挑出来,然后用逗号连接起来
// 例如,传入参数words=['a','bb','ccc','d','e']
// 返回字符串a,d,e
public static String filterThenConcat(Set<String> words) {
return words.stream()
.filter(word->word.length()==1)
.collect(Collectors.joining(","));
}

public static void main(String[] args) {
System.out.println(filterThenConcat(new LinkedHashSet<>(Arrays.asList("a", "bb", "ccc", "d", "e"))));
}
}

并发流

  • parallelStream()
  • 可以通过并发提⾼互相独⽴的操作的性能
  • 在正确使⽤的前提下,可以获得近似线性的性能提升
  • 但是!使⽤要⼩⼼,性能要测试,如果你不知道⾃⼰在做什
    么,就忘了它吧。

统计 1~1000的质数

  • 我们可以把它分为两个部分 [1~500] [501~1000]
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
package com.io.demo;

import java.util.stream.IntStream;

public class Xxx {
public static void main(String[] args) {
long t0 = System.currentTimeMillis();
IntStream.range(1,1000_000).filter(Xxx::isPrime).count();

System.out.println(System.currentTimeMillis() - t0);

long t1 = System.currentTimeMillis();
IntStream.range(1,1000_000).parallel().filter(Xxx::isPrime).count();

System.out.println(System.currentTimeMillis() - t1);
}

public static boolean isPrime(int num){
double sqrt = Math.sqrt(num);
if (num < 2) {
return false;
}
if (num == 2 || num == 3) {
return true;
}
if (num % 2 == 0) {// 先判断是否为偶数,若偶数就直接结束程序
return false;
}
for (int i = 3; i <= sqrt; i+=2) {
if (num % i == 0) {
return false;
}
}
return true;
}
}

// 424
// 81
// 性能差距非常大

练习

参考⽂献

  • Effective Java Item 42-48 (专门讲stream)