採坑系列 Collectors.toMap

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,需要搞清楚可能會發生的問題,每個參數的含義。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章