问题描述
在实际开发中经常会有类似的这种代码,想要按类的某一个属性对列表中的元素分组。
例如:
有一些学生,然后根绝他们的年龄对他们进行分组。可以写出如下代码。
public class UnsupportedOperationExceptionDemo {
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Student {
private String name;
private Integer age;
}
public static void main(String[] args) {
// 初始化几个学生
List<Student> studentList = new ArrayList<>();
studentList.add(new Student("张三", 18));
studentList.add(new Student("李四", 19));
studentList.add(new Student("王五", 18));
studentList.add(new Student("赵六", 20));
// 根据年龄对这个分组
Map<Integer, List<Student>> map = new HashMap<>();
for (Student student : studentList) {
if (map.containsKey(student.getAge())) {
List<Student> students = map.get(student.getAge());
students.add(student);
} else {
map.put(student.getAge(), Arrays.asList(student));
}
}
}
}
运行结果:
这是为什么呢?
原因分析
在for循环中如果集合中没有这个年龄的学生,则需要创建一个List然后将元素加入,所以偷了一下懒,直接使用了Arrays.asList(student)
这样的代码。
问题就出在这一行代码!!!!
看一下asList
的源码,发现也是new ArrayList(a)
不过仔细看一下这个ArrayList
的全限定名是java.util.Arrays.ArrayList
而不是我们平常使用的java.util.ArrayList
那这两个有何不同?为什么会报错?
因为上面的代码调用了java.util.Arrays.ArrayList
对象的add
方法,这个类并没有重写add
方法,所以直接使用父类java.util.AbstractList
中的方法,而父类的add
方法就是会抛出UnsupportedOperationException
异常
解决方案
方案一:创建java.util.ArrayList
对象来存放元素
方案二:使用Java 8的Stream流来处理
Map<Integer, List<Student>> map =
studentList
.stream()
.collect(Collectors.groupingBy(Student::getAge));