我正在从方法返回一个不可修改的地图。如何确保尝试修改返回的映射的任何代码都会出现编译时错误,而不是运行时错误?
我的课程:
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 :(得分: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);
}
请注意,如果它们不是不可变类的实例,这不会妨碍调用者改变值对象。
答案 1 :(得分:2)
默认地图可以修改,期限。
如果您希望它不可修改,您必须编写自己的类,其中Map为变量,再次实现您需要的所有方法并将其传递给地图。
由于您不需要.put()方法,因此跳过该方法。
答案 2 :(得分: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()方法返回可修改的集合,因此您还需要包装它们返回的值。
答案 3 :(得分:0)
你不能这样做。
不可修改的集合是实现选项,而不是类型。
你能做的最好的事情就是用javadoc来记录它,比如:
/**
* Gets the map
* @returns An unmodifiable Map
*/
public Map<String, Bar> getMap(){
return Collections.unmodifiableMap(aMap);
}
答案 4 :(得分:0)
您不能使用标准类。使用标准类,您知道它是不可修改的唯一方法是尝试修改它并接收UnsupportedOperationException
。
您可以通过创建自己的UnmodifiableMap
实现来实现编译时检查,该实现在内部使用正常Map
(可能是不可修改的)。它将具有通常的“读取”操作,并且它们将被委托给基础Map
。它不会有通常的“写”操作。我猜你也想要一个方法来返回底层的Map
(或它的副本),以增强与其他代码的互操作性。
答案 5 :(得分: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);
}
}
}