java8出的流操作,由于可以快速转化为map并且便于代码阅读,所以推荐使用java8语法转化List为map。
这里给出例子:
public class GroupByTest {
public class Student{
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Student name(String name){
this.name = name;
return this;
}
public Student age(Integer age){
this.age = age;
return this;
}
}
@Test
public void groupBy(){
List<Student> studentList = new ArrayList<>();
studentList.add(new Student().age(20).name("张三"));
studentList.add(new Student().age(20).name("李四"));
studentList.add(new Student().age(21).name("王五"));
Map<Integer, Student> collect = studentList.stream().collect(Collectors.toMap(Student::getAge, v -> v));
}
}
结果上诉代码报错
java.lang.IllegalStateException: Duplicate key com.example.demo.GroupByTest$Student@22680f52
at java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133)
at java.util.HashMap.merge(HashMap.java:1254)
分析原因:
Collectors源码
public static <T, K, U>
Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper) {
return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new);
}
public static <T, K, U, M extends Map<K, U>>
Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper,
BinaryOperator<U> mergeFunction,
Supplier<M> mapSupplier) {
BiConsumer<M, T> accumulator
= (map, element) -> map.merge(keyMapper.apply(element),
valueMapper.apply(element), mergeFunction);
return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID);
}
merge方法源码
上面的源码可以看到。
Collectors.toMap 传入了一个 参数
throwingMerger()
我们看这个方法中代码,发现直接扔了一个异常。
private static <T> BinaryOperator<T> throwingMerger() {
return (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); };
}
remappingFunction 一直传到了merge 方法中 。
- 判断key对应的value是否有值,如果有值,执行 入参 remappingFunction 的操作。但是我们传入的是 抛出异常,所以。这里直接抛出了异常;
我们打断点调试看到
解决方法,调用重载方法
public static <T, K, U>
Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper,
BinaryOperator<U> mergeFunction) {
return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
}
自己传入 function
可以看到,这里已经对重复值进行了覆盖。
解决方案:调用重载方法,传入处理的 function
Collectors.toMap(Student::getAge, v -> v, (u, v) -> v)
总结:使用api时,如果遇到重载的api,需要搞清楚可能会发生的问题,每个参数的含义。