2017-07-19 93 views
2

我正在實現自己的收集器,它使用合併函數。不幸的是,對於我的一些情況,我無法重用拋出以下JDK合併函數IllegalStateExceptionJava中throwingMerger的替代方案8

java.util.stream.Collectors#throwingMerger 

它發生由於它具有私人訪問修飾符和其他(非內部)類的訪問受到限制。 然而,javadoc中說以下內容:

這可以被用來執行的假設,收集要素是不同的

但是,正如我看到,Java文檔是過時的。它不能使用。問題是JDK是否爲java開發人員提供了類似的功能(類似的方法,常量等),還是應該自己編寫它?異常消息是不正確:

+0

這並不是真的那麼難寫自己。我已經寫了幾十次(儘管我寧願我沒有,但那是另一回事)。 –

+6

'(a,b) - > {throw new IllegalStateException(); }'有整個合併函數。 –

+3

javadoc沒有過期。它正確地聲明該方法可以被其他類的方法用於描述的目的。如果您查看[* generated * javadoc](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html#method.summary),而不是源代碼,則您你會發現這個方法甚至不存在。 javadoc不適用於您,但適用於JDK開發人員。 – Andreas

回答

3

throwingMerger()如下

private static <T> BinaryOperator<T> throwingMerger() { 
    return (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); }; 
} 

你可以添加一個類似的方法來你的代碼庫,但你應該知道,合併的根本問題的實施。該函數的第一個參數是舊值,而不是關鍵。此功能無法使用該密鑰,因此無法爲此合併功能生成包含重複密鑰的異常消息。

因此,由於在這個地方解決這個問題是不可能的,所以這個函數是一個實現細節是很好的,所以它可以在沒有任何兼容性限制的情況下被移除。

爲了提供一個合理的診斷,而不toMap合併功能需要一個完全不同的實施比toMap用(非拋)合併功能,所以toMaptoConcurrentMap收集器沒有合併功能已被完全重寫。

請求投擲合併功能的常見原因是沒有toMap超載接受沒有合併功能的地圖Supplier。但由於投擲合併不會做正確的事情,當重複的鍵應該被拒絕時需要完全不同的方法,您可以使用this answer的收集器來代替。它的一個稍微改進的版本是

public static <T, K, V, M extends Map<K,V>> Collector<T, ?, M> toMap(
     Function<? super T, ? extends K> keyMapper, 
     Function<? super T, ? extends V> valueMapper, 
     Supplier<M> mapSupplier) { 

    return Collector.of(mapSupplier, 
      (m,t) -> putUnique(m, keyMapper.apply(t), 
            Objects.requireNonNull(valueMapper.apply(t))), 
      (m1,m2) -> { 
       if(m1.isEmpty()) return m2; 
       if(!m2.isEmpty()) m2.forEach((k,v) -> putUnique(m1, k, v)); 
       return m1; 
      }); 
} 
private static <K, V> void putUnique(Map<K, V> map, K key, V v1){ 
    V v2 = map.putIfAbsent(key, v1); 
    if(v2 != null) throw new IllegalStateException(
     String.format("Duplicate key %s (values %s and %s)", key, v1, v2)); 
} 
+0

謝謝!這個答案提供了我所期望的更多信息。 – dvelopp

+0

@Holger,你再次襲擊......美麗!我甚至沒有問過...... thx – Eugene