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

4

5 回答 5

15

这样的类和实用方法有什么用?

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

此外,如果您返回一个Map空的结果,那么不必每次都创建一个新对象很方便 - 每个空映射都等效于其他每个空映射,因此可以使用单个实例。

于 2013-08-02T08:47:45.927 回答
7

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

于 2013-08-02T08:56:14.933 回答
4

对于您的情况,我想对 immutable 的最佳解释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 item 43 (Return empty arrays or collections, not nulls),建议您返回一个空 Collection,这样您在开发时就不必包含 null-array 操作代码。您也可以将其称为Null-Object-Pattern

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

    到目前为止,一切都很好。假设您决定使用EMPTY_MAPfrom Collections(如果有,为什么不呢?)。您在几个地方返回空地图,但在其中一些地方您想修改它。您将引用 EMPTY_MAP 修改为使用此引用的所有代码(这使我们回到第 1 点。还记得 EMPTY_MAP 中的更改吗?)。

  3. 这个原因是为了减少内存和类似的东西。如果它不是不可变的,并且您每次想要一个空映射时都会创建新实例,那将导致您(您可以说是严重的)内存(不是泄漏,而是)性能(我不太了解这个术语,但是你明白了)。也许你听说过singleton,这是一回事。

你去吧。这是您需要不可变 EMPTY_MAP 的主要 3 个原因(我目前能想到的)。

一个解决你问题的方法,你不应该使用 EMPTY_MAP,你应该自己创建一个。这并不难,而且你摆脱了这些讨厌的(可怕的)不可变的东西。

祝你好运!

于 2013-08-02T09:38:41.813 回答
1

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

于 2013-08-02T08:52:41.777 回答
1

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

于 2013-08-02T09:06:47.103 回答