1

我正在从一个方法返回一个不可修改的地图。如何确保任何试图修改返回映射的代码都会出现编译时错误,而不是运行时错误?

我的课:

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

我可以更改退货类型吗?我可以添加适当的注释吗?

4

6 回答 6

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

请注意,如果它们不是不可变类的实例,这不会妨碍调用者改变值对象。

于 2013-09-25T15:36:49.800 回答
2

默认地图是可修改的,期间。

如果您希望它不可修改,则必须编写自己的类,该类具有 Map 作为变量,再次实现所需的所有方法并将其传递给 map。

由于您不想要 .put() 方法,因此您跳过该方法。

于 2013-09-25T15:33:47.450 回答
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.

}

请注意 values() 和 entrySet() 方法返回可修改的集合,因此您也需要包装它们的返回值。

于 2013-09-25T15:39:40.663 回答
0

您不能使用标准课程来做到这一点。对于标准类,您知道它不可修改的唯一方法是尝试修改它并接收UnsupportedOperationException.

您可以通过创建自己的内部UnmodifiableMap使用正常Map(可能不可修改)的实现来实现编译时检查。它将具有通常的“读取”操作,它们将被委托给底层的Map. 它不会有通常的“写”操作。我猜您可能还希望有一个方法可以返回底层Map(或它的副本)以增强与其他代码的互操作性。

于 2013-09-25T15:39:06.633 回答
0

You can not do it.

An unmodifiable Collection is an implementation choice, not a type.

The best you could do is to document it with javadoc, something like:

/**
 * Gets the map
 * @returns An unmodifiable Map
 */
public Map<String, Bar> getMap(){
    return Collections.unmodifiableMap(aMap);
}
于 2013-09-25T15:28:19.860 回答
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);
    }
  }

}
于 2013-09-25T15:48:47.643 回答