为什么我们需要不可变的空Map?

10
/**
 * Returns the empty map (immutable).  This map is serializable.
 *
 * <p>This example illustrates the type-safe way to obtain an empty set:
 * <pre>
 *     Map&lt;String, Date&gt; s = Collections.emptyMap();
 * </pre>
 * Implementation note:  Implementations of this method need not
 * create a separate <tt>Map</tt> object for each call.   Using this
 * method is likely to have comparable cost to using the like-named
 * field.  (Unlike this method, the field does not provide type safety.)
 *
 * @see #EMPTY_MAP
 * @since 1.5
 */
@SuppressWarnings("unchecked")
public static final <K,V> Map<K,V> emptyMap() {
    return (Map<K,V>) EMPTY_MAP;
}

上述函数返回一个不可更改的空映射。

public static final Map EMPTY_MAP = new EmptyMap<>();

EmptyMap类如下所示

/**
 * @serial include
 */
private static class EmptyMap<K,V>
    extends AbstractMap<K,V>
    implements Serializable
{
    private static final long serialVersionUID = 6428348081105594320L;

    public int size()                          {return 0;}
    public boolean isEmpty()                   {return true;}
    public boolean containsKey(Object key)     {return false;}
    public boolean containsValue(Object value) {return false;}
    public V get(Object key)                   {return null;}
    public Set<K> keySet()                     {return emptySet();}
    public Collection<V> values()              {return emptySet();}
    public Set<Map.Entry<K,V>> entrySet()      {return emptySet();}

    public boolean equals(Object o) {
        return (o instanceof Map) && ((Map<?,?>)o).isEmpty();
    }

    public int hashCode()                      {return 0;}

    // Preserves singleton property
    private Object readResolve() {
        return EMPTY_MAP;
    }
}

这个类和实用方法有什么用?我试过了

Map myMap = Collections.emptyMap();
myMap.put("Name","John");

我遇到了Exception in thread "main" java.lang.UnsupportedOperationException的问题,因为这个集合是不可改变的,所以它不支持修改。那么这样的数据结构有什么用呢?


3
我不确定,但我猜这对于类似于空对象模式的东西可能有帮助。不要从方法返回空引用,而是返回一个空映射。 - Asha
可能是 [Collections.emptyMap() vs new HashMap()] 的重复问题 (https://dev59.com/vmUq5IYBdhLWcg3wC79Q)。 - assylias
5个回答

15
这个类和实用方法有什么用处?
如果您返回一个Map结果,将其设置为不可变通常很有用...例如,可以创建一个包装您自己的“真实”数据的不可变映射,而无需创建完整的副本或信任调用方不会改变它。
此外,如果您返回的Map结果为空,不需要每次都创建一个新对象-每个空映射等效于其他每个空映射,因此可以使用单个实例。

6

4

针对您的情况,我猜测解释immutable Collections.EMPTY_MAP 最好的方式如下:

  1. The field is declared as public (for ease of access). If you don't make it final, this means you can come at any time and have a little code like this:

    //somewhere in your program (or someone else's)
    Collections.EMPTY_MAP = new EmptyMap<"String","String">("unwantedKey","unwantedValue");
    
    //what do you actually want to do
    Map myMap = Collections.emptyMap();
    //you would expect an empty map, but you will get something else
    

    this will be very bad for you as you can probably see that you're program behaviour will be wrong.

  2. If you read Effective Java 2nd edition item 43 (Return empty arrays or collections, not nulls) it is recommended to return an empty Collection, so you wont have to include null-array manipulation code when developing. You may refer to this as Null-Object-Pattern as well.

    OK, so what have that to do with immutable EMPTY_COLLECTION (or MAP in your case)? Imagine that you would use many methods in your class, and you call a method that makes groups of elements from a collection, and returns a collection of the groups, unless (random condition inserted here).

    So far so good. Let's say that you decide to use the EMPTY_MAP from Collections (if it's there, why not?). You return the empty map in several places, but in some of them you want to modify it. You modify the reference EMPTY_MAP to all of your code that uses this reference (This brings us back to number 1. Remember the change in EMPTY_MAP?).

  3. This reason if for memory reduction and stuff like that. If it wouldn't be immutable and you would create new instances every time you wanted an empty map, that would cause you (you could say severe) memory (not leaks, but) performance (I don't quite know the term, but you get the idea). Maybe you heard of singleton, this is the same thing.

这里是主要的三个原因(我能想到的)为什么你需要一个不可变的 EMPTY_MAP:
1. 避免 Null 引用异常。 2. 使代码更加安全,避免其他人修改了这个 map。 3. 省略创建新 map 的开销。
对于你的问题,解决方案是:不应该使用 EMPTY_MAP,而应该自己创建一个。这并不难,而且可以摆脱这些让人讨厌(甚至可怕)的不可变对象。
祝你好运!

1

1
这应该是一条注释,而不是一个答案。 - Adam Siemion

1
它(与emptyList和emptySet一起使用)用于返回一个空的集合,而无需每次实例化一个新对象。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接