文章目录
前言
刚开始我只会使用普通的for、while循环,最多就增强for循环,后来在项目上看到其他同事在用,看起来很新颖、简洁的样子,然后我也开始尝试使用,用顺手之后发现是真的香。在使用的过程中,有些时候,不能完全实现自己所想的,也没少百度,所以呢,就想着把这些稍微高级一点、难一点的用法记录下来,
数据准备:
public class BlogMain1 {
@Data
@AllArgsConstructor
static class User{
private String username;
private String gender;
private String group;
private Integer age;
}
@Data
@AllArgsConstructor
static class Group {
private String name;
private String desc;
}
private List<User> users = new ArrayList<User>(){{
add(new User("张无忌","男","明教",23));
add(new User("金毛狮王--谢逊","男","明教",47));
add(new User("紫衫龙王--黛绮丝","女","明教",32));
add(new User("白眉鹰王--殷天正","男","明教",38));
add(new User("青翼蝠王--韦一笑","男","明教",35));
add(new User("张三丰","男","武当",56));
add(new User("宋远桥","男","武当",42));
add(new User("张翠山","男","武当",41));
add(new User("殷梨亭","男","武当",37));
add(new User("灭绝师太","女","峨眉",51));
add(new User("周芷若","女","峨眉",21));
add(new User("宋青书","男","峨眉",22));
add(new User("圆真","男","少林",35));
add(new User("空智","男","少林",47));
}};
}
一. 分组 groupingBy
基础用法
1. 按照某个属性分组
代码
// key是门派名称,value是门派里面所有的人
Map<String, List<User>> collect = users.stream().collect(Collectors.groupingBy(User::getGroup));
结果
{武当=[BlogMain1.User(username=张三丰, gender=男, group=武当, age=56), BlogMain1.User(username=宋远桥, gender=男, group=武当, age=42), BlogMain1.User(username=张翠山, gender=男, group=武当, age=41), BlogMain1.User(username=殷梨亭, gender=男, group=武当, age=37)], 明教=[BlogMain1.User(username=张无忌, gender=男, group=明教, age=23), BlogMain1.User(username=金毛狮王--谢逊, gender=男, group=明教, age=47), BlogMain1.User(username=紫衫龙王--黛绮丝, gender=女, group=明教, age=32), BlogMain1.User(username=白眉鹰王--殷天正, gender=男, group=明教, age=38), BlogMain1.User(username=青翼蝠王--韦一笑, gender=男, group=明教, age=35)], 峨眉=[BlogMain1.User(username=灭绝师太, gender=女, group=峨眉, age=51), BlogMain1.User(username=周芷若, gender=女, group=峨眉, age=21), BlogMain1.User(username=宋青书, gender=男, group=峨眉, age=22)], 少林=[BlogMain1.User(username=圆真, gender=男, group=少林, age=35), BlogMain1.User(username=空智, gender=男, group=少林, age=47)]}
2. 分组统计
// key是门派名称,value是门派人数
Map<String, Long> collect1 = users.stream().collect(Collectors.groupingBy(User::getGroup,
Collectors.counting()));
// {武当=4, 明教=5, 峨眉=3, 少林=2}
3. 分组求和
// key是门派名称,value是门派人年龄之和
Map<String, Long> collect2 = users.stream().collect(Collectors.groupingBy(User::getGroup,
Collectors.summingLong(User::getAge)));
// {武当=176, 明教=175, 峨眉=94, 少林=82}
4. 自定义分组条件------按姓名长度分组
代码
// 按照姓名长度分组
Map<Integer, List<User>> collect3 = users.stream().collect(Collectors.groupingBy(x -> x.username.length()));
结果
{2=[BlogMain1.User(username=圆真, gender=男, group=少林, age=35), BlogMain1.User(username=空智, gender=男, group=少林, age=47)], 3=[BlogMain1.User(username=张无忌, gender=男, group=明教, age=23), BlogMain1.User(username=张三丰, gender=男, group=武当, age=56), BlogMain1.User(username=宋远桥, gender=男, group=武当, age=42), BlogMain1.User(username=张翠山, gender=男, group=武当, age=41), BlogMain1.User(username=殷梨亭, gender=男, group=武当, age=37), BlogMain1.User(username=周芷若, gender=女, group=峨眉, age=21), BlogMain1.User(username=宋青书, gender=男, group=峨眉, age=22)], 4=[BlogMain1.User(username=灭绝师太, gender=女, group=峨眉, age=51)], 8=[BlogMain1.User(username=金毛狮王--谢逊, gender=男, group=明教, age=47)], 9=[BlogMain1.User(username=紫衫龙王--黛绮丝, gender=女, group=明教, age=32), BlogMain1.User(username=白眉鹰王--殷天正, gender=男, group=明教, age=38), BlogMain1.User(username=青翼蝠王--韦一笑, gender=男, group=明教, age=35)]}
5. 自定义分组条件------按照多个字段分组
代码
// 多个属性分组,按照门派和性别分组
Map<String, List<User>> collect4 = users.stream().collect(Collectors.groupingBy(x -> x.getGroup() + "_" + x.getGender()));
结果
{少林_男=[BlogMain1.User(username=圆真, gender=男, group=少林, age=35), BlogMain1.User(username=空智, gender=男, group=少林, age=47)], 明教_男=[BlogMain1.User(username=张无忌, gender=男, group=明教, age=23), BlogMain1.User(username=金毛狮王--谢逊, gender=男, group=明教, age=47), BlogMain1.User(username=白眉鹰王--殷天正, gender=男, group=明教, age=38), BlogMain1.User(username=青翼蝠王--韦一笑, gender=男, group=明教, age=35)], 峨眉_男=[BlogMain1.User(username=宋青书, gender=男, group=峨眉, age=22)], 武当_男=[BlogMain1.User(username=张三丰, gender=男, group=武当, age=56), BlogMain1.User(username=宋远桥, gender=男, group=武当, age=42), BlogMain1.User(username=张翠山, gender=男, group=武当, age=41), BlogMain1.User(username=殷梨亭, gender=男, group=武当, age=37)], 明教_女=[BlogMain1.User(username=紫衫龙王--黛绮丝, gender=女, group=明教, age=32)], 峨眉_女=[BlogMain1.User(username=灭绝师太, gender=女, group=峨眉, age=51), BlogMain1.User(username=周芷若, gender=女, group=峨眉, age=21)]}
高级用法
只是个人感觉比上面的高级一些,可能在大佬看来本质上都一样,只是更复杂了一点点。
1. 改变分组后的key和value
在上面的分组中,key还好,在4和5自定义条件分组中,改变了key。但是value呢?好像都是定死了,普通的分组就是该对象的集合,求和、统计就是一个数字,能不能我自己来规定返回的value类型呢?比如我要按照门派分组,得到每个门派里面每个人的名字,不需要其他的性别、年龄信息
代码
// 按照门派分组,分组后 key 为Group对象, value变成String名字
Map<Group, List<String>> collect2 = users.stream()
.collect(Collectors.groupingBy(x -> new Group(x.getGroup(), x.getGroup() + "的描述"),
Collectors.mapping(User::getUsername, Collectors.toCollection(ArrayList::new))));
结果
{BlogMain1.Group(name=明教, desc=明教的描述)=[张无忌, 金毛狮王--谢逊, 紫衫龙王--黛绮丝, 白眉鹰王--殷天正, 青翼蝠王--韦一笑], BlogMain1.Group(name=武当, desc=武当的描述)=[张三丰, 宋远桥, 张翠山, 殷梨亭], BlogMain1.Group(name=少林, desc=少林的描述)=[圆真, 空智], BlogMain1.Group(name=峨眉, desc=峨眉的描述)=[灭绝师太, 周芷若, 宋青书]}
2. 多级分组
先按照一个条件分组,在分组的基础上再按照另一个条件分组
代码
// 多级分组,先按照门派分组,门派里面再按照名字长度分组
Map<Group, Map<Integer, List<User>>> collect3 = users.stream().collect(
Collectors.groupingBy(x -> new Group(x.getGroup(), x.getGroup() + "的描述"),
Collectors.groupingBy(x -> x.username.length())));
结果
{BlogMain1.Group(name=明教, desc=明教的描述)={3=[BlogMain1.User(username=张无忌, gender=男, group=明教, age=23)], 8=[BlogMain1.User(username=金毛狮王--谢逊, gender=男, group=明教, age=47)], 9=[BlogMain1.User(username=紫衫龙王--黛绮丝, gender=女, group=明教, age=32), BlogMain1.User(username=白眉鹰王--殷天正, gender=男, group=明教, age=38), BlogMain1.User(username=青翼蝠王--韦一笑, gender=男, group=明教, age=35)]}, BlogMain1.Group(name=武当, desc=武当的描述)={3=[BlogMain1.User(username=张三丰, gender=男, group=武当, age=56), BlogMain1.User(username=宋远桥, gender=男, group=武当, age=42), BlogMain1.User(username=张翠山, gender=男, group=武当, age=41), BlogMain1.User(username=殷梨亭, gender=男, group=武当, age=37)]}, BlogMain1.Group(name=少林, desc=少林的描述)={2=[BlogMain1.User(username=圆真, gender=男, group=少林, age=35), BlogMain1.User(username=空智, gender=男, group=少林, age=47)]}, BlogMain1.Group(name=峨眉, desc=峨眉的描述)={3=[BlogMain1.User(username=周芷若, gender=女, group=峨眉, age=21), BlogMain1.User(username=宋青书, gender=男, group=峨眉, age=22)], 4=[BlogMain1.User(username=灭绝师太, gender=女, group=峨眉, age=51)]}}
3. 分组排序
就是先分组, 再每组分别排序, 经常写SQL的小伙伴可能经常碰到这个问题, steam api 就非常简单
代码
Map<String, List<User>> userMap = users.stream().collect(Collectors.groupingBy(User::getGender,
Collectors.mapping(u -> u, Collectors.collectingAndThen(Collectors.toList(),
sortedStudents -> sortedStudents.stream().sorted((Comparator.comparing(User::getAge)))
.collect(Collectors.toList())))));
userMap.forEach((k, v) -> {
System.err.println("k: " + k);
v.forEach(System.err::println);
});
结果
k: 女
BlogMain1.User(username=周芷若, gender=女, group=峨眉, age=21)
BlogMain1.User(username=紫衫龙王--黛绮丝, gender=女, group=明教, age=32)
BlogMain1.User(username=灭绝师太, gender=女, group=峨眉, age=51)
k: 男
BlogMain1.User(username=宋青书, gender=男, group=峨眉, age=22)
BlogMain1.User(username=张无忌, gender=男, group=明教, age=23)
BlogMain1.User(username=青翼蝠王--韦一笑, gender=男, group=明教, age=35)
BlogMain1.User(username=圆真, gender=男, group=少林, age=35)
BlogMain1.User(username=殷梨亭, gender=男, group=武当, age=37)
BlogMain1.User(username=白眉鹰王--殷天正, gender=男, group=明教, age=38)
BlogMain1.User(username=张翠山, gender=男, group=武当, age=41)
BlogMain1.User(username=宋远桥, gender=男, group=武当, age=42)
BlogMain1.User(username=金毛狮王--谢逊, gender=男, group=明教, age=47)
BlogMain1.User(username=空智, gender=男, group=少林, age=47)
BlogMain1.User(username=张三丰, gender=男, group=武当, age=56)
4. 我在项目中的使用例子
暂时就想到这么多,欢迎补充