为什么我们有不可变的空地图?

时间:2013-08-02 08:44:19

标签: java collections map immutability

/**
 * 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 因为不可变的集合不支持修改。那么这种数据结构的用途是什么?

5 个答案:

答案 0 :(得分:13)

  

这种类和实用方法的用途是什么?

如果你要返回一个Map结果,那么它通常是有用的......例如,你可以创建一个包含你自己的“真实”数据的不可变映射,而不是必须创建完整副本,或信任调用者不要改变它。

另外,如果你要返回一个空的Map结果,那么每次都不必创建一个新对象 - 每个空地图都等同于其他每个空地图,所以使用起来很好单个实例。

答案 1 :(得分:7)

这有助于实现Null对象设计模式http://en.wikipedia.org/wiki/Null_Object_pattern,即返回空映射而不是null

答案 2 :(得分:4)

对于您的情况,我想对不可变Collections.EMPTY_MAP的最佳解释如下:

  1. 该字段被声明为公共字段(以便于访问)。如果你没有做到最终,这意味着你可以随时来,并有一些像这样的代码:

    //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
    

    这对你来说非常糟糕,因为你可能会发现你的程序行为是错误的。

  2. 如果您阅读Effective Java 2nd edition第43项(返回空数组或集合,而不是空值),建议返回一个空集合,这样您就不必在开发时包含空数组操作代码。您也可以将其称为Null-Object-Pattern

    好的,那么与不可变的EMPTY_COLLECTION(或你的情况下的MAP)有什么关系呢? 想象一下,您将在类中使用许多方法,并调用一个方法,该方法从一个集合中生成一组元素,并返回这些组的集合,除非(此处插入随机条件)。

    到目前为止一切顺利。假设您决定使用EMPTY_MAP中的Collections(如果它在那里,为什么不呢?)。您在几个地方返回空地图,但在其中一些地方您想要修改它。您将引用EMPTY_MAP修改为使用此引用的所有代码(这会将我们带回到数字1.请记住EMPTY_MAP中的更改?)。

  3. 这个原因如果用于减少内存和类似的东西。如果它不是不可变的,你每次想要一个空地图就会创建新实例,这会导致你(你可以说是严重的)内存(不是泄漏,但是)性能(我不太清楚这个术语,但是你明白了。也许你听说过singleton,这是一回事。

  4. 你去吧。这是您需要不可变EMPTY_MAP的主要原因(我现在可以想到)。

    对于您的问题的解决方案,您不应该使用EMPTY_MAP,您应该自己创建一个。这并不难,你摆脱了这些讨厌(可怕)不可改变的事情。

    祝你好运!

答案 3 :(得分:1)

这个堆栈溢出问题可能会有所帮助:使用不可变空集(Collections.emptyMap() vs new HashMap()

答案 4 :(得分:0)

它(与空List和空Set一起使用)返回一个空集合,而不需要每次都实例化一个新对象。