迭代映射条目集

2022-09-02 12:27:39

我需要迭代一个映射的条目集,我不知道它的参数化类型。

当迭代这样的条目集时,为什么这不编译?

public void myMethod(Map anyMap) {
    for(Entry entry : anyMap.entrySet()) {
        ...
    }
}

但是这个编译:

public void myMethod(Map anyMap) {
    Set<Entry> entries = anyMap.entrySet();
    for(Entry entry : entries) {
        ...
    }
}

这也编译(我不能使用这个,因为我不知道地图的类型):

public void myMethod(Map<String, String> stringMap) {
    for(Entry<String,String> entry : stringMap.entrySet()) {
        ...
    }
}

答案 1

您在第一个错误中遇到的错误是:

Type mismatch: cannot convert from element type Object to Map.Entry

这是因为编译器会转换 FOR-IN 循环:

for (Entry entry : anyMap.entrySet()) {
}

自:

for (Iterator i = anyMap.entrySet().iterator(); i.hasNext();) {
    Entry e = i.next(); // not allowed
}

你的第二个例子有效,但只能通过作弊!您正在执行未经检查的强制转换以返回到 .SetSet<Entry>

Set<Entry> entries = anyMap.entrySet(); // you get a compiler warning here
for (Entry entry : entries) {
}

成为:

Set<Entry> entries = anyMap.entrySet();
for (Iterator<Entry> i = entries.iterator(); i.hasNext(); ) {
    Entry e = (Entry) i.next(); // allowed
}

更新

如注释中所述,类型信息在这两个示例中都丢失了:因为编译器的原始类型擦除规则。

为了提供向后兼容性,原始类型实例的所有方法都将替换为其已擦除的对应方法。所以,因为你是一个原始类型,所以它都被删除了。包括其方法:您的原始类型实例将被强制使用擦除后的版本:。MapSet<Map.Entry<K, V>> entrySet();Set entrySet()


答案 2

这是因为您使用了原始类型 Map,因此 map.entrySet() 会为您提供一个非参数化的 Set,作为回报,该 Set 在迭代时产生 Object,而不是 Entry。

一个简单但优雅的解决方案是使用Map<?,?>,它仍然允许您传递任何Map,但另一方面强制map.entrySet()具有返回值Set<Entry>:

public void test(Map<?,?> map) {        
    for(Entry e : map.entrySet()){
        Object key = e.getKey();
        Object value = e.getValue();
    }       
}

推荐