简体   繁体   English

返回不可修改的地图

[英]Returning unmodifiable map

I have a Map as follows: 我有一个地图,如下所示:

Map<String,Map<String,Object>>

Given a key,I would be returned the Map. 给定一把钥匙,我将被退回地图。
What is the recommended way to make the returned Map immutable. 建议使用什么方法使返回的Map不可变。
This essentially means that: 这实质上意味着:
Map is immutable (no edits/deletes/add) 地图是不可变的(无编辑/删除/添加)
Underlying Object are immutable (no edits) 底层对象是不可变的(无编辑)

We have no option to make Object immutable . 我们没有使Object不变的选择。

What you have to do is make a deep copy of the returning Map. 您要做的是对返回的Map进行深层复制。

Java HashMap - deep copy Java HashMap-深层副本

You can make each map unmodifiable, then make the whole map unmodifiable. 您可以使每个地图不可修改,然后使整个地图不可修改。

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);
}

The real problem is that you still provide access to the value in the map. 真正的问题是您仍然提供对地图中值的访问。 You could create copies of those objects, but that doesnt solve the problem. 您可以创建这些对象的副本,但这不能解决问题。 Either make the object class immutable or create a Wrapper class for them which disables the setter methods. 使对象类不可变,或为它们创建一个Wrapper类,以禁用setter方法。

You can make an unmodifiable map whose map values are also unmodifiable by extending AbstractMap . 您可以通过扩展AbstractMap来制作一个其地图值也无法修改的不可修改地图。

To implement an unmodifiable map, the programmer needs only to extend this class and provide an implementation for the entrySet method, which returns a set-view of the map's mappings. 要实现不可修改的地图,程序员只需扩展此类并为entrySet方法提供实现,该方法将返回地图映射的set-view。 Typically, the returned set will, in turn, be implemented atop AbstractSet . 通常,返回的集合将依次在AbstractSet之上实现。 This set should not support the add or remove methods, and its iterator should not support the remove method. 该集合不支持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);
                    }
                };
            }
        };
    }
}

The abstract collections are really great classes to be familiar with because they make a lot of problems like this fairly trivially solvable without writing a new container from scratch. 抽象集合确实是非常好的类,因为它们会产生很多这样的问题,这些问题相当容易解决,而无需从头开始编写新容器。

There is no way to make an immutable object in Java, aside from writing an immutable object. 除了编写不可变对象之外,没有其他方法可以用Java制作不可变对象。 Java has no feature like eg const in C++. Java没有像C ++中的const这样的功能。

One way to do this without actually instantiating a new object is to write interfaces as follows, then return the ImmutableFoo any time you don't want to expose the setter: 在不实际实例化新对象的情况下执行此操作的一种方法是按如下方式编写接口,然后在您不想公开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; }
}

Otherwise, if Foo is a class you are unable to change, you have to write something like the following: 否则,如果Foo是您无法更改的类,则必须编写类似以下内容:

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

Either of those could be used eg in combination with the unmodifiable AbstractMap example. 例如,可以与不可修改的AbstractMap示例结合使用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM