实现 Map.entrySet 时出现 'mismatching null constraints' 错误(Java8,Eclipse)

Getting 'mismatching null constraints' error when implementing Map.entrySet (Java8, Eclipse)

我收到错误...

The return type is incompatible with 'Set<Map.Entry<K,T>>' returned from Map<K,T>.entrySet() (mismatching null constraints)

...当实现 Map 并像这样覆盖 Map.entrySet 时:

package org.abego.util;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
...    
public abstract class MyMap<K, T> implements Map<K, T> {
    private Map<K, T> map = new LinkedHashMap<>();

    @Override
    public Set<java.util.Map.Entry<K, T>> entrySet() {
        return map.entrySet();
    }
    ...
}

org.abego.util 将默认的空性定义为 @NonNull:

@org.eclipse.jdt.annotation.NonNullByDefault
package org.abego.util;

我发现消除错误的唯一方法是 'remove the default nullness annotation' for entrySet 使用 @NonNullByDefault({}) 注释:

package org.abego.util;
...
import org.eclipse.jdt.annotation.NonNullByDefault;

public abstract class MyMap<K, T> implements Map<K, T> {
    ...
    @Override
    @NonNullByDefault({})
    public Set<java.util.Map.Entry<K, T>> entrySet() {
        return map.entrySet();
    }
    ...
}

虽然这确实有效,但我想知道这是否是修复错误的正确方法。

(我使用的是 Eclipse 4.5 (Mars) 和 jdk1.8.0_60。)

您正试图覆盖此方法:

Set<Map.Entry<K, V>> entrySet();

使用有效签名为

的方法
@NonNull Set<@NonNull Map.Entry<K, V>> entrySet();

这是一个不兼容的覆盖,可以通过这个调用者来证明:

Set<Map.Entry<Foo,Bar>> entries = someMap.entrySet();
entries.add(null);

如果 someMap 的类型为 MyMap,则 entries 的元素类型为 @NonNull,但 java.util.Map.entrySet() 的合约承诺 Set 其中允许 null 个元素(集合未指定其元素为空)。在同一个对象 entries 上混合两个合同(@NonNull 和未指定)将破坏假定非空元素的客户端。

查看 entrySet() 的 Javadoc,但是可以安全地假设 Map.entrySet()always return a Set 与非空元素。因此,问题的根源在于 java.util.Map.entrySet() 没有空注释。

自 Eclipse Mars 以来,这可以通过 JRE 的 external null annotations. You can tell the compiler that the return type of Map.entrySet() is in fact @NonNull Set<@NonNull Map.Entry<K,V>>, either by applying the Annotate command in the IDE, or by putting the following snippet into a file java/util/Map.eea inside a directory that has been configured as the location for external annotations 来克服:

class java/util/Map

entrySet
 ()Ljava/util/Set<Ljava/util/Map$Entry<TK;TV;>;>;
 ()L1java/util/Set<L1java/util/Map$Entry<TK;TV;>;>;

有了这样的外部注释,您的程序将被 JDT 的空分析接受。