2017-05-24 62 views
0

我有一個圖如下:返回不可修改的映射

Map<String,Map<String,Object>> 

給定一個鍵,我將返回地圖。
推薦使返回的Map不可變的方法是什麼?
這基本上意味着:
地圖是不變的(無修改/刪除/添加)
底層對象是不可變的(無編輯)

我們沒有其他選擇,使對象不可改變。

+0

[返回一個不可修改的映射]可能的副本(https://stackoverflow.com/questions/7066618/returning-an-unmodifiable-map) –

+1

沒有辦法指定一個對象是不可變的,除了寫一個不可變的目的。正如我理解你的問題,你實際上並沒有真正想讓地圖不可變,而是詢問如何使地圖中的對象不可變。那是對的嗎?換句話說,你基本上需要像C++'const'這樣的東西,但在Java中不存在。你必須編寫一個包裝對象的代理,並且不提供setter或throws異常。使用界面有幫助。 – Radiodef

+1

你實際上需要不可變的'Object' _forfor?不知道這一點,很難提供任何有用的建議。 – Rook

回答

1

可以讓每個地圖不可修改,然後使整個地圖不可修改。

public Map<String,Map<String,Object>> makeUnModifiable(Map<String,Map<String,Object>> a){ 
    for(Entry<String, Map<String, Object>> e:a.entrySet()){ 
    e.setValue(Collections.unmodifiableMap(e.getValue())); 
    } 
    return Collections.unmodifiableMap(a); 
} 

真正的問題是,您仍然提供對地圖中值的訪問。您可以創建這些對象的副本,但這並不能解決問題。可以使對象類不可變或爲它們創建一個禁用setter方法的Wrapper類。

+0

這不會使問題中的對象本身不可修改。 – RealSkeptic

+0

@RealSkeptic是真的。這隻能以非常有限的方式完成,每個方法都需要知道對象類。 – f1sh

0

通過擴展AbstractMap,您可以製作一張不可修改的地圖,其地圖值也不可修改。

要實現不可修改的映射,程序員僅需要擴展此類並提供entrySet方法,它返回地圖的映射的一組視圖的實現。通常,返回的集合將依次在AbstractSet之上實現。該集不應該支持addremove方法,其迭代器不應該支持remove方法。

package mcve; 

import java.util.*; 

public final class UnmodifiableMapOfMaps<K, L, V> extends AbstractMap<K, Map<L, V>> { 
    // Optionally Map<? extends K, ? extends Map<? extends L, ? extends V>> 
    // but it would make the code a lot more difficult to read. 
    private final Map<K, Map<L, V>> map; 

    public UnmodifiableMapOfMaps(Map<K, Map<L, V>> map) { 
     this.map = Objects.requireNonNull(map); 
    } 

    // Additionally override size(), get(), etc., entirely optionally. 
    // Doing so would merely be an optimization since AbstractMap 
    // implements those methods via the entrySet() iterator. 

    @Override 
    public Set<Entry<K, Map<L, V>>> entrySet() { 
     return new AbstractSet<Entry<K, Map<L, V>>>() { 
      @Override 
      public int size() { 
       return map.size(); 
      } 

      @Override 
      public Iterator<Entry<K, Map<L, V>>> iterator() { 
       return new Iterator<Entry<K, Map<L, V>>>() { 
        private final Iterator<Entry<K, Map<L, V>>> it = map.entrySet().iterator(); 

        @Override 
        public boolean hasNext() { 
         return it.hasNext(); 
        } 

        @Override 
        public Entry<K, Map<L, V>> next() { 
         // Return the Entry as an immutable Entry with an 
         // unmodifiableMap as the value. 
         Entry<K, Map<L, V>> entry = it.next(); 
         K   key = entry.getKey(); 
         Map<L, V> val = Collections.unmodifiableMap(entry.getValue()); 
         return new SimpleImmutableEntry<>(key, val); 
        } 
       }; 
      } 
     }; 
    } 
} 

抽象的集合是真正偉大的階級熟悉,因爲他們做了很多的問題,像這個相當平凡解不從頭開始編寫一個新的容器。

除了編寫不可變對象外,沒有辦法在Java中創建不可變對象。 Java沒有像例如const在C++中。要做到這一點,而無需實際實例化一個新的對象

一種方法是編寫接口如下,然後返回ImmutableFoo你不想暴露二傳手任何時間:

interface ImmutableFoo { 
    int getValue(); 
} 
interface MutableFoo extends ImmutableFoo { 
    void setValue(int value); 
} 
class Foo implements MutableFoo { 
    private int value; 
    public Foo(int value)      { this.value = value; } 
    @Override public int getValue()   { return value;  } 
    @Override public void setValue(int value) { this.value = value; } 
} 

否則,如果Foo是一個你無法改變的課程,你必須寫下如下內容:

class FooAccessor { 
    private final Foo foo; 
    public FooAccessor(Foo foo) { this.foo = Objects.requireNonNull(foo); } 
    public int getValue()  { return foo.getValue(); } 
} 

其中任何一個都可以使用eg結合不可修改的AbstractMap示例。