2013-09-25 15 views
1

我從方法返回一個不可修改的映射。我如何確保任何試圖修改返回映射的代碼都會得到編譯時錯誤,而不是運行時錯誤?如何聲明該方法正在返回Collections.unmodifiableMap

我的類:

public class Foo 
{ 
    private final Map<String, Bar> aMap; 

    public Foo() 
    { 
    ... 
    } 

    public Map<String, Bar> getMap(){ 
     return Collections.unmodifiableMap(aMap); 
    } 
} 

我想這是創建一個編譯時錯誤:

Foo foo = new Foo(); 
Map<String, Bar> m = foo.getMap(); 
m.put('key',null); // user should be notified that the map is unmodifiable here, not at run time 

我是否可以改變返回類型? 我可以添加適當的註釋嗎?

+0

如果Method的返回類型是java.util.Map,則無法實現此功能。您只能將返回類型更改爲包裝「Map」的自定義類。 – jlordo

+0

這很好,我怎麼改變返回類型? – Boundless

+0

也許你不應該在這種情況下返回整個地圖 – doctorlove

回答

4

你就可以創建

class ReadOnlyMap<K, V> { 

    private final Map<K, V> map; 

    public ReadOnlyMap(Map<K, V> map) { 
     this.map = map; 
    } 

    public V get(Object key) { 
     return map.get(key); 
    } 

    // also implement size() method 
    // and everything else you want to expose 
} 

一類,並使用它作爲您的方法的返回類型。然後你的方法是

public ReadOnlyMap<String, Bar> getMap() { 
    return new ReadOnlyMap(aMap); 
} 

要注意的是這不會妨礙呼叫者變異值的對象,如果他們不是一成不變的類的實例。

+2

作爲另一個答案指出,一定要注意這一點: 「要注意的是()的值的entrySet和()方法返回修改的集合,所以你會還需要包裝它們的返回值。「 – StormeHawke

0

你不能這樣做。

一個不可修改的Collection是一個實現的選擇,而不是一個類型

你能做的最好是用javadoc的記錄它,像:

/** 
* Gets the map 
* @returns An unmodifiable Map 
*/ 
public Map<String, Bar> getMap(){ 
    return Collections.unmodifiableMap(aMap); 
} 
+0

那我該如何讓其他開發者知道不要打電話呢? – Boundless

+0

@無邊。你可以記錄你的getMap()方法,指定它返回一個「Unmodifiable」映射。你無法實現更多的目標。 –

+0

Collections.unmodifiableMap(aMap)的返回類型是一個具體的類http://www.docjar.com/docs/api/java/util/Collections$UnmodifiableMap.html。只是它是包私營和不可見的外java.util包 – krishnakumarp

2

默認地圖是可以修改的,期限。

如果您希望它不可修改,您必須編寫自己的具有Map作爲變量的類,再次實施您需要的所有方法並將其傳遞到地圖。

由於您不需要.put()方法,因此可以跳過該方法。

0

你不能用標準類來做。使用標準類,您知道它是不可修改的唯一方法是嘗試修改它並獲得UnsupportedOperationException

您可以通過創建自己的UnmodifiableMap實現來實現編譯時檢查,該實現在內部使用正常的Map(可能不可修改)。它將具有通常的「讀取」操作,並且它們將被委託給基礎Map。它不會有通常的「寫入」操作。我猜你會希望有一個方法可以返回潛在的Map(或其副本)以增強與其他代碼的互操作性。

1

您可以創建一個UnmodifiableMap對象,該對象具有Map接口的所有讀取方法,但缺少寫入方法。這個對象會包裹你想要的地圖。它看起來像:

public class UnmodifiableMap<K, V> { 

    private final Map<K, V> map; 

    public UnmodifiableMap(final Map<K, V> map) { 
     this.map = map; 
    } 

    public boolean containsKey(final K key) { 
     return map.containsKey(key); 
    } 

    public V get(final K key) { 
     return map.get(key); 
    } 

    // And so on. 

} 

要注意的是()的值的entrySet和()方法返回修改集合,所以你需要來包裝他們的返回的值了。

+0

如果你想遵守'Map'儘可能接近,'get()'方法應該把'Object'作爲參數,而不是'K';否則,這就是要走的路。 – jlordo

0

這似乎接近你所要求的。它不會給出錯誤,但它確實會給出警告!

public class Solid { 
    // My map has no put. 
    public interface Map<K, V> extends java.util.Map<K, V> { 
    /** 
    * Put to the Map. 
    * 
    * @deprecated SolidMap is unmodifiable. put() will fail! 
    */ 
    @Deprecated 
    @Override 
    V put(K key, V value); 

    } 

    // Could also do this for lists etc. 

    // Helper wrappers from each kind of map. 
    public class HashMap<K, V> extends java.util.HashMap<K, V> implements Solid.Map<K, V> { 
    } 

    public class TreeMap<K, V> extends java.util.TreeMap<K, V> implements Solid.Map<K, V> { 
    } 
    //... 

    // Test only. 
    public void test() { 
    Solid.Map<String, String> sm = new Solid.HashMap<>(); 
    // Warning that put is deprecated! 
    String put = sm.put("Key", "Value"); 
    } 

    public static void main(String args[]) { 
    try { 
     new Solid().test(); 
    } catch (Throwable t) { 
     t.printStackTrace(System.err); 
    } 
    } 

} 
相關問題