返回不可修改的地图

时间:2017-05-24 13:03:49

标签: java

我有一张地图如下:

Map<String,Map<String,Object>>

鉴于钥匙,我将返回地图 使返回的Map不可变的推荐方法是什么 这基本上意味着:
地图是不可变的(没有编辑/删除/添加)
底层对象是不可变的(无编辑)

我们没有选择使对象不可变。

3 个答案:

答案 0 :(得分:1)

您需要做的是复制返回的地图。

Java HashMap - deep copy

答案 1 :(得分: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类。

答案 2 :(得分: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没有像以下那样的功能C ++中的const

在没有实际实例化新对象的情况下执行此操作的一种方法是按如下方式编写接口,然后在您不想要公开setter时返回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(); }
}

可以使用其中任何一种,例如与不可修改的AbstractMap示例结合使用。