1

我实现了在这里找到的非常好的排序解决方案:

static <K,V extends Comparable<? super V>> SortedSet<Map.Entry<K,V>>
entriesSortedByValues(Map<K,V> map) {

    SortedSet<Map.Entry<K,V>> sortedEntries = new TreeSet<Map.Entry<K,V>>(

        new Comparator<Map.Entry<K,V>>() {
            @Override
            public int compare(Map.Entry<K,V> e1, Map.Entry<K,V> e2) {
                int res = e1.getValue().compareTo(e2.getValue());
                return res != 0 ? res : 1;
            }
        }
    );

    sortedEntries.addAll(map.entrySet());
    return sortedEntries;
}

该代码似乎工作得很好。然而,FindBugs 抱怨这一行:

sortedEntries.addAll(map.entrySet());

投诉是:

错误:添加条目集的元素可能会由于在 com.local.sem.util.MapUtil.entriesSortedByValues(Map) 中重用 Map.Entry 对象而失败

entrySet() 方法允许返回底层 Map 的视图,其中单个 Entry 对象在迭代期间被重用并返回。从 Java 1.6 开始,IdentityHashMap 和 EnumMap 都这样做了。在遍历这样的 Map 时,Entry 值仅在您进行下一次迭代之前有效。例如,如果您尝试将这样的 entrySet 传递给 addAll 方法,那么事情就会大错特错。

信心:正常,等级:麻烦(14)
模式:DMI_ENTRY_SETS_MAY_REUSE_ENTRY_OBJECTS
类型:DMI,类别:BAD_PRACTICE(不良做法)

谁能告诉我这意味着什么,或者它是否真的与这个特定的代码相关?

4

2 回答 2

3

这是问题的一个简单示例:

Map<String,String> map = new IdentityHashMap<String,String>();
map.put("a", "1");
map.put("b", "2");
Iterator<Entry<String,String>> i = map.entrySet().iterator();
Entry<String,String> e1 = i.next();
System.out.println("first key is: " + e1.getKey());
Entry<String,String> e2 = i.next();
System.out.println("first key is now: " + e1.getKey());

使用 Java 6,这将打印:

first key is: a
first key is now: b

这是因为对 i.next() 的第二次调用返回与第一次相同的条目,但它更改了存储在该条目中的值。

如果我将 IdentityHashMap 更改为 HashMap,则返回的每个条目都是不同的,因此 e1.getKey() 不会更改。

于 2012-08-08T17:59:23.643 回答
-3

entrySet() 方法允许返回底层 Map 的视图,其中单个 Entry 对象在迭代期间被重用并返回。从 Java 1.6 开始,IdentityHashMap 和 EnumMap 都这样做了。在遍历这样的 Map 时,Entry 值仅在您进行下一次迭代之前有效。例如,如果您尝试将这样的 entrySet 传递给 addAll 方法,那么事情就会大错特错。

请阅读链接了解更多详情。http://findbugs.sourceforge.net/bugDescriptions.html#DMI_ENTRY_SETS_MAY_REUSE_ENTRY_OBJECTS

于 2012-08-08T01:56:31.650 回答