Java8:利用Stream分组筛选数据

引起

有下面这一组数据,需要按关联字段、级别进行分组,第一时间想到的可能是在数据库使用SQL语句直接进行操作.但由于一些原因,无法在数据库中进行操作(这里仅用作示例,真实情况可能嵌套了好几层),鉴于Java 1.8发布很久很久了,就用Java 1.8的新特性实验了一下.

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
//因使用随机ID,因此部分数据可能出现不一致.
//ID[随便生成,仅用作示例] >>>>>>>> 名称 >>>>>> 关联的字段 >>>>>> 级别
9602177f-adb1-430a-a4a0-2287490bd9c2 >>>>>>> name38 >>>>>>> 550 >>>>>>> 1
13db2e97-0968-4d37-abcf-bd9afe88b1e4 >>>>>>> name39 >>>>>>> 1000 >>>>>>> 2
f1ed8688-a374-4d05-89a9-baaa6e8be546 >>>>>>> name64 >>>>>>> 550 >>>>>>> 1
c69c52b7-f327-436c-9bdc-6ffadb1f19a7 >>>>>>> name50 >>>>>>> 550 >>>>>>> 1
f0179d92-8fe5-4a46-95b0-c9f5671a9f70 >>>>>>> name79 >>>>>>> 1000 >>>>>>> 2
346e6f7f-7b1c-4c1c-b859-c197b55292f8 >>>>>>> name9 >>>>>>> 1000 >>>>>>> 2
ce3277ca-7b84-434f-8af0-0c7f06dc0ebb >>>>>>> name48 >>>>>>> 550 >>>>>>> 1
590bfddb-f9fd-4f4d-ab30-f71416b886ea >>>>>>> name75 >>>>>>> 1000 >>>>>>> 2
24884d2d-e403-456b-94b1-43fb11ec9e66 >>>>>>> name4 >>>>>>> 550 >>>>>>> 1
5dfb13ca-426e-4787-92b7-324ef58880b0 >>>>>>> name49 >>>>>>> 1000 >>>>>>> 2
ef44d0ee-0e44-4970-bdd2-87637a067260 >>>>>>> name40 >>>>>>> 550 >>>>>>> 1
cd815427-c410-4506-acf4-097871781955 >>>>>>> name4 >>>>>>> 550 >>>>>>> 1
785123b7-2584-47fc-92f8-8c850709b40b >>>>>>> name23 >>>>>>> 1000 >>>>>>> 2
e77b0f49-bd0d-4e31-80aa-29a0b9938a22 >>>>>>> name65 >>>>>>> 1000 >>>>>>> 2
64a81271-8020-453c-8b80-e7eb96e66fe6 >>>>>>> name52 >>>>>>> 550 >>>>>>> 1
921254ce-720a-4345-a10f-8382e6a361f5 >>>>>>> name9 >>>>>>> 1000 >>>>>>> 2
aecda534-d683-451e-9c7d-6927127d7d87 >>>>>>> name38 >>>>>>> 550 >>>>>>> 1
9309324f-c815-4b0c-9352-b3555f712235 >>>>>>> name29 >>>>>>> 1000 >>>>>>> 2
448736f6-0f76-4266-acdf-7b1faf2d8c24 >>>>>>> name14 >>>>>>> 550 >>>>>>> 1
039bdd87-5523-4be9-b0ac-ee305cf50a8c >>>>>>> name41 >>>>>>> 1000 >>>>>>> 2
065d2a1c-5c1b-45bb-9fce-d021c77addce >>>>>>> name71 >>>>>>> 1000 >>>>>>> 2
917c9e08-9cdd-45bf-803b-108f1b22de1a >>>>>>> name39 >>>>>>> 1000 >>>>>>> 2
caa7bacd-c08a-4ea7-a4ea-5ca844d82eab >>>>>>> name46 >>>>>>> 550 >>>>>>> 1
241f7f44-a387-4439-b44e-7d7d3e40528c >>>>>>> name8 >>>>>>> 550 >>>>>>> 1
f38befef-ffc4-4bad-88e9-46723db76371 >>>>>>> name10 >>>>>>> 550 >>>>>>> 1
72d4e95c-498d-4e4e-b0b3-3fc1b6b4ce40 >>>>>>> name54 >>>>>>> 550 >>>>>>> 1
bfb137e3-20e6-4b42-bb63-a0b7411f7e1b >>>>>>> name26 >>>>>>> 550 >>>>>>> 1
aa3c8aea-b387-44c6-8aaf-dc8d946510ff >>>>>>> name6 >>>>>>> 550 >>>>>>> 1
84a1cef4-dbac-44ce-a083-0650d5a074c1 >>>>>>> name0 >>>>>>> 550 >>>>>>> 1
8d1a87ad-daa7-4043-941e-1ab367ad063b >>>>>>> name18 >>>>>>> 550 >>>>>>> 1

java标志
image-2436

过程

首先定义了一个实体类[用来组织数据]:

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
//Question.java

package com.company;

/**
 * Created by Administrator on 2016/4/6.
 */
public class Question {

    private String id ;// id
    private String name; // 名称
    private String parent;// 关联父级
    private String level; // 级别

    public Question() {
    }

    public Question(String id, String name, String parent, String level) {
        this.id = id;
        this.name = name;
        this.parent = parent;
        this.level = level;
    }

    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 String getParent() {
        return parent;
    }

    public void setParent(String parent) {
        this.parent = parent;
    }

    public String getLevel() {
        return level;
    }

    public void setLevel(String level) {
        this.level = level;
    }
}

实体定义好之后,在这里我使用了一个List来模拟从数据库中取出的数据,并且使用了随机数达到”随机”的假象.

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
//Main.java
package com.company;


import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * @author prd.
 * @version 2015.12.10
 */
public class Main {
    public static void main(String[] args) {
        //使用一个List模拟从数据库中取出来的数据
        List<Question> lists = new ArrayList<>();
        //往List中填充模拟数据
        for (int i = 0; i < 30; i++) {
            Question q = null;
            //控制填充的几率
            int random = (int) (Math.random() * 80);
            if (random % 2 == 0) {
                //使用UUID模拟ID属性
                q = new Question(String.valueOf(UUID.randomUUID()), "name" + random, "550", "1");
            } else {
                q = new Question(String.valueOf(UUID.randomUUID()), "name" + +random, "1000", "2");
            }
            lists.add(q);
        }

        //先输出List中的数据.
        //点击forEach可以查看相关注释:forEach是一种简化后的循环,同for类似.
        lists.forEach(x -> {
            System.out.println(x.getId() + " >>>>>>> " + x.getName() + " >>>>>>> " + x.getParent() + " >>>>>>> " +x.getLevel());
        });

        //筛选相关数据
        /*
             lists
                .stream() // 将List转换成一个"流",这是Java 1.8添加的新特性.关于更多Stream的知识,可参考:http://www.liaoxuefeng.com/article/001411309538536a1455df20d284b81a7bfa2f91db0f223000
                //通过java.util.stream.Stream接口的collect对List进行"收集操作",
                //也就是通过collect对List进行分组,
                //collect接收一个Collector接口的实现(通常使用Collectors,Collectors内部实现了Collector)
                .collect(Collectors.groupingBy(Question::getLevel, Collectors.groupingBy(Question::getParent)))
                //下面都是遍历过程,collect进行分组之后返回一个Map.第二个是我们需要的.
                .forEach((r, a) ->
                        a.forEach((x, y) ->
                                y.forEach(xy -> System.out.println(xy.getId() + ">>>>>>>>>" + xy.getName()))));
         */
        lists
                .stream()
                .collect(Collectors.groupingBy(Question::getLevel, Collectors.groupingBy(Question::getParent)))
                .forEach((r, a) ->
                        a.forEach((x, y) ->
                                y.forEach(xy -> System.out.println(xy.getId() + ">>>>>>>>>" + xy.getName()))));
        /*
                关于Stream可以参考:http://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html 官方文档.
                Java 1.8新增很多类,变化比较大的就是:Lambda表达式,Stream API,新的java.util.Time时间库,default关键字等等.
                关于Java 1.8的变化可以参考:http://openjdk.java.net/projects/jdk8/milestones
         */
    }
}

输出结果如下:

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
//因使用随机ID,因此部分数据可能出现不一致.
cd2ac555-b9d8-40a2-9a1c-921a21335a96 >>>>>>> name4 >>>>>>> 550 >>>>>>> 1
1438b3e8-12c3-4dc7-875e-8317ef9b74db >>>>>>> name70 >>>>>>> 550 >>>>>>> 1
f5198af8-2f4d-46c3-815e-731ed81b6104 >>>>>>> name5 >>>>>>> 1000 >>>>>>> 2
16709764-24d2-43dc-954c-23b8537f2151 >>>>>>> name53 >>>>>>> 1000 >>>>>>> 2
4e70afba-4efc-436a-b0b9-88275da6edfe >>>>>>> name41 >>>>>>> 1000 >>>>>>> 2
09be4cbf-b28e-41e1-b91a-6445da4877ee >>>>>>> name0 >>>>>>> 550 >>>>>>> 1
955bc785-ef53-489d-bf5a-7b70046cd044 >>>>>>> name19 >>>>>>> 1000 >>>>>>> 2
50bed251-bdd4-49d0-9845-b8f00206c934 >>>>>>> name15 >>>>>>> 1000 >>>>>>> 2
5a5be641-57b7-43cd-bd20-c908377a2197 >>>>>>> name23 >>>>>>> 1000 >>>>>>> 2
cae3ab42-f576-4ca5-a9ea-2fd345be5c91 >>>>>>> name28 >>>>>>> 550 >>>>>>> 1
786448d6-48b7-468d-9e57-dc67c3980b2e >>>>>>> name76 >>>>>>> 550 >>>>>>> 1
40547eb8-6022-4259-a5fc-9ffa24052e9e >>>>>>> name4 >>>>>>> 550 >>>>>>> 1
a0880786-b59f-4b73-8c10-034803429287 >>>>>>> name64 >>>>>>> 550 >>>>>>> 1
16b058ff-a869-4ceb-8673-f31fb329823a >>>>>>> name27 >>>>>>> 1000 >>>>>>> 2
ea4c61d9-07d5-40e3-beb7-afa1693fb9cf >>>>>>> name18 >>>>>>> 550 >>>>>>> 1
f08e69df-3fa3-42ff-a152-f801c1c3e0b2 >>>>>>> name29 >>>>>>> 1000 >>>>>>> 2
0659902e-89ec-4a37-8c70-516fad0364fc >>>>>>> name45 >>>>>>> 1000 >>>>>>> 2
a51046c3-9ce8-4933-97de-6c27599c57cb >>>>>>> name27 >>>>>>> 1000 >>>>>>> 2
8865d74a-e4d4-4f68-849a-223ceb3bff3b >>>>>>> name59 >>>>>>> 1000 >>>>>>> 2
94b144bf-8d24-4602-b29a-2e7fc954bd85 >>>>>>> name21 >>>>>>> 1000 >>>>>>> 2
52fa654b-1447-40cf-93f3-d3904c85dcac >>>>>>> name75 >>>>>>> 1000 >>>>>>> 2
bbd114fa-0dcf-4957-ad97-56227886b61e >>>>>>> name7 >>>>>>> 1000 >>>>>>> 2
7b7e3017-1a85-4dca-bd86-fdfdc468fa31 >>>>>>> name67 >>>>>>> 1000 >>>>>>> 2
bcaf91ed-eaa0-4306-bb24-54c26511a3f7 >>>>>>> name44 >>>>>>> 550 >>>>>>> 1
181965c2-302d-45b5-9ee3-7ea7eb349f87 >>>>>>> name67 >>>>>>> 1000 >>>>>>> 2
eb600cbf-64e8-4f47-a3d7-cc8d06cd16e5 >>>>>>> name30 >>>>>>> 550 >>>>>>> 1
a78eed33-2adf-4078-88ef-4be494c217e4 >>>>>>> name1 >>>>>>> 1000 >>>>>>> 2
409e7d31-751c-4497-aa2b-702306d3bb5f >>>>>>> name4 >>>>>>> 550 >>>>>>> 1
964e7f5e-0a3c-4578-bcd1-be54744a899d >>>>>>> name53 >>>>>>> 1000 >>>>>>> 2
68d5027e-5b16-4ac2-9dc7-d01ed55dfb60 >>>>>>> name54 >>>>>>> 550 >>>>>>> 1
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
cd2ac555-b9d8-40a2-9a1c-921a21335a96>>>>>>>>>name4>>>>>>>>>1>>>>>>>>>550
1438b3e8-12c3-4dc7-875e-8317ef9b74db>>>>>>>>>name70>>>>>>>>>1>>>>>>>>>550
09be4cbf-b28e-41e1-b91a-6445da4877ee>>>>>>>>>name0>>>>>>>>>1>>>>>>>>>550
cae3ab42-f576-4ca5-a9ea-2fd345be5c91>>>>>>>>>name28>>>>>>>>>1>>>>>>>>>550
786448d6-48b7-468d-9e57-dc67c3980b2e>>>>>>>>>name76>>>>>>>>>1>>>>>>>>>550
40547eb8-6022-4259-a5fc-9ffa24052e9e>>>>>>>>>name4>>>>>>>>>1>>>>>>>>>550
a0880786-b59f-4b73-8c10-034803429287>>>>>>>>>name64>>>>>>>>>1>>>>>>>>>550
ea4c61d9-07d5-40e3-beb7-afa1693fb9cf>>>>>>>>>name18>>>>>>>>>1>>>>>>>>>550
bcaf91ed-eaa0-4306-bb24-54c26511a3f7>>>>>>>>>name44>>>>>>>>>1>>>>>>>>>550
eb600cbf-64e8-4f47-a3d7-cc8d06cd16e5>>>>>>>>>name30>>>>>>>>>1>>>>>>>>>550
409e7d31-751c-4497-aa2b-702306d3bb5f>>>>>>>>>name4>>>>>>>>>1>>>>>>>>>550
68d5027e-5b16-4ac2-9dc7-d01ed55dfb60>>>>>>>>>name54>>>>>>>>>1>>>>>>>>>550
f5198af8-2f4d-46c3-815e-731ed81b6104>>>>>>>>>name5>>>>>>>>>2>>>>>>>>>1000
16709764-24d2-43dc-954c-23b8537f2151>>>>>>>>>name53>>>>>>>>>2>>>>>>>>>1000
4e70afba-4efc-436a-b0b9-88275da6edfe>>>>>>>>>name41>>>>>>>>>2>>>>>>>>>1000
955bc785-ef53-489d-bf5a-7b70046cd044>>>>>>>>>name19>>>>>>>>>2>>>>>>>>>1000
50bed251-bdd4-49d0-9845-b8f00206c934>>>>>>>>>name15>>>>>>>>>2>>>>>>>>>1000
5a5be641-57b7-43cd-bd20-c908377a2197>>>>>>>>>name23>>>>>>>>>2>>>>>>>>>1000
16b058ff-a869-4ceb-8673-f31fb329823a>>>>>>>>>name27>>>>>>>>>2>>>>>>>>>1000
f08e69df-3fa3-42ff-a152-f801c1c3e0b2>>>>>>>>>name29>>>>>>>>>2>>>>>>>>>1000
0659902e-89ec-4a37-8c70-516fad0364fc>>>>>>>>>name45>>>>>>>>>2>>>>>>>>>1000
a51046c3-9ce8-4933-97de-6c27599c57cb>>>>>>>>>name27>>>>>>>>>2>>>>>>>>>1000
8865d74a-e4d4-4f68-849a-223ceb3bff3b>>>>>>>>>name59>>>>>>>>>2>>>>>>>>>1000
94b144bf-8d24-4602-b29a-2e7fc954bd85>>>>>>>>>name21>>>>>>>>>2>>>>>>>>>1000
52fa654b-1447-40cf-93f3-d3904c85dcac>>>>>>>>>name75>>>>>>>>>2>>>>>>>>>1000
bbd114fa-0dcf-4957-ad97-56227886b61e>>>>>>>>>name7>>>>>>>>>2>>>>>>>>>1000
7b7e3017-1a85-4dca-bd86-fdfdc468fa31>>>>>>>>>name67>>>>>>>>>2>>>>>>>>>1000
181965c2-302d-45b5-9ee3-7ea7eb349f87>>>>>>>>>name67>>>>>>>>>2>>>>>>>>>1000
a78eed33-2adf-4078-88ef-4be494c217e4>>>>>>>>>name1>>>>>>>>>2>>>>>>>>>1000
964e7f5e-0a3c-4578-bcd1-be54744a899d>>>>>>>>>name53>>>>>>>>>2>>>>>>>>>1000