List集合中一般有很多实体对象,每个对象都有自己的属性,有时我们需要将具备某个相同属性的对象进行分组处理,传统写法比较好理解也容易实现,但代码量比较大不太优美,而且要多次循环,而Java8给我们提供了新方法,一行代码搞定分组,不仅让潘老师体会到了什么叫优雅地写代码,更体会到了要与时俱进,不然写的代码真是越来越out了!下面,潘老师来对比下这两种实现方式的差距。
一、前期准备
首先我们新建一个User
类,代码如下:
public class User { private String name; private String sex; private String grade; public User(String name, String sex,String grade) { this.name = name; this.sex = sex; this.grade = grade; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getGrade() { return grade; } public void setGrade(String grade) { this.grade = grade; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", sex='" + sex + '\'' + ", grade='" + grade + '\'' + '}'; } }
二、传统写法
我们先使用传统写法将List集合中的User
按照sex
属性进行分组:
import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class Test { public static void main(String[] args) { List<User> users = new ArrayList<>(); users.add(new User("小明","男","1班")); users.add(new User("小红","女","1班")); users.add(new User("小张","男","2班")); users.add(new User("小兰","女","1班")); users.add(new User("小紫","女","2班")); Map<String,List<User>> userMap = new HashMap<>(); for (User user : users) { String name = user.getName(); if (userMap.containsKey(name)) { userMap.get(name).add(user); }else { List<User> list = new ArrayList<>(); list.add(user); userMap.put(name,list); } } System.out.println(userMap); } }
三、优雅写法
1、我们先根据sex
来分组,代替上面的传统写法:
import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class Test { public static void main(String[] args) { List<User> users = new ArrayList<>(); users.add(new User("小明","男","1班")); users.add(new User("小红","女","1班")); users.add(new User("小张","男","2班")); users.add(new User("小兰","女","1班")); users.add(new User("小紫","女","2班")); // 核心代码(返回Map集合,key就是分组的属性,value就是分组后的集合) Map<String, List<User>> userMap = users.stream().collect(Collectors.groupingBy(User::getSex)); System.out.println(userMap); } }
输出结果:
{女=[User{name=’小红’, sex=’女’, grade=’1班’}, User{name=’小兰’, sex=’女’, grade=’1班’}, User{name=’小紫’, sex=’女’, grade=’2班’}], 男=[User{name=’小明’, sex=’男’, grade=’1班’}, User{name=’小张’, sex=’男’, grade=’2班’}]}
2、groupBy还支持嵌套分组,我们可以实现先根据sex
分组,对分组后的每个List
数据再根据grade
分组,其代码如下:
import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class Test { public static void main(String[] args) { List<User> users = new ArrayList<>(); users.add(new User("小明","男","1班")); users.add(new User("小红","女","1班")); users.add(new User("小张","男","2班")); users.add(new User("小兰","女","1班")); users.add(new User("小紫","女","2班")); // 核心代码(返回Map集合,也是嵌套的,最外层key就是sex,内层map的key是grade) Map<String,Map<String,List<User>>> userMap = users.stream().collect(Collectors.groupingBy(User::getSex,Collectors.groupingBy(User::getGrade))); System.out.println(userMap); }
输出结果:
{女={2班=[User{name=’小紫’, sex=’女’, grade=’2班’}], 1班=[User{name=’小红’, sex=’女’, grade=’1班’}, User{name=’小兰’, sex=’女’, grade=’1班’}]}, 男={2班=[User{name=’小张’, sex=’男’, grade=’2班’}], 1班=[User{name=’小明’, sex=’男’, grade=’1班’}]}}
好了,以后再也不用再为集合分组闹心了,也就一行代码的事儿!
Java8
的Stream
是新特性,除了collect
还有很多对集合高阶操作的方法,具体的可以参考:菜鸟教程 Java8 Stream