1. 程式人生 > 其它 >java.lang.IllegalStateException: Duplicate key

java.lang.IllegalStateException: Duplicate key

技術標籤:Java知識點javajdk1.8stream

文章目錄

java.lang.IllegalStateException: Duplicate key

// list轉map key重複
java.lang.IllegalStateException: Duplicate key DealerImageInfo

異常

出現原因

當使用java.util.Collectionstream()方法將集合轉為Map時,如果key有重複就會丟擲此異常。

**例:**如果有形如下程式碼

//將List型別的entityList轉為entityMap,Entity的id欄位作為key,entity物件為value
//Entity::getId:獲取Entity的id欄位
//Function.identity()等同於x->x,將輸入作為輸出,即將遍歷的物件最為value
Map<Long, Entity> entityMap= entityList.stream().collect(Collectors.toMap(Entity::getId, Function.identity()));

此時如果entityListentity

物件的id有重複,就會丟擲此異常;

解決方法

  1. 保證待轉化的List中各物件作為key的欄位不重複(業務方式處理,不做介紹);
  2. 使用toMap的過載方法。
Map<Long, Entity> entityMap= entityList.stream().collect(Collectors.toMap(Entity::getId, Function.identity(), (var1, var2) -> var1));

這種方式是toMap()方法新加一個引數,該引數是重複資料的處理規則。示例中使用這種方式是保留第一條資料,讀者也可以根據需求寫第三個引數。
自此異常處理完畢,下面寫一些toMap的過載方法。

番外:toMap的過載方法

toMap方法的三種過載:

toMap(Function<? super T, ? extends K>, Function<? super T, ? extends U>):Collector<T, ?, Map<K,U>>
toMap(Function<? super T, ? extends K>, Function<? super T, ? extends U>, BinaryOperator<U>):Collector<T, ?, Map<K,U>> 
toMap(Function<? super T, ? extends K>, Function<? super T, ? extends U>, BinaryOperator<U>, Supplier<M>):Collector<T, ?, M>

這三個過載方法最終執行方法是最後一個,前兩個都是加入預設引數後呼叫第三個方法;
方法引數含義如下:

  1. 獲取MapKey
  2. 獲取Mapvalue
  3. key重複時合併規則
  4. 最終的返回型別 (不傳時預設返回Map型別)
    第一個方法第3個引數預設置為throwingMerger()方法,表示有重複時丟擲異常,就是題目中的異常
    第二個方法可以自定義第3個引數,定義為(entity1,entity2) -> entity1,表示保留第一個資料
    原始碼:
	// 只有兩個引數的toMap
	// 這個方法預設的重複資料處理規則是呼叫throwingMerger()方法
	// 返回的Map是HashMap
    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);
    }
    
    // throwingMerger方法對重複資料直接丟擲異常,這個異常就是我們見到的異常
    private static <T> BinaryOperator<T> throwingMerger() {
        return (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); };
    }
	// 三個引數的方法可以指定重複資料的處理規則
	// 返回的Map是HashMap
    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);
    }
    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);
    }