如何摆脱 TreeMap 的 eclipse neon 中的 "Null type safety" 警告

How to get rid of "Null type safety" warning in eclipse neon for TreeMap

如何消除此示例代码中的警告。

我将 Eclipse Neon 与 Java 1.8 和 org.eclipse.jdt.annotation_2.1.0

一起使用
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;

@NonNullByDefault
public class NullAnnotationTest4 {

    public static void main(String[] args) {

        final TreeMap<@Nullable Integer, @Nullable String> treeMap = new TreeMap<>();

        treeMap.put(3,  "Test1");
        treeMap.put(null, null);

        //This produces the warning
        final Set<@Nullable Entry<@Nullable Integer, @Nullable String>> set = treeMap.entrySet();

        for (final Iterator<@Nullable Entry<@Nullable Integer, @Nullable String>> it = set.iterator(); it.hasNext(); ) {

            final Entry<@Nullable Integer, @Nullable String> entry = it.next();

            if (entry != null && entry.getKey() == null && entry.getValue() != null)
                System.out.println(entry.getKey()+" is mapped to "+entry.getValue());
        }

    }
}

警告是:

Null type safety (type annotations): 
The expression of type 
'Set<Map.Entry<@Nullable Integer,@Nullable String>>' 
needs unchecked conversion to conform to 
'Set<Map.@Nullable Entry<@Nullable Integer,@Nullable String>>'

我尝试了几种@Nullable 和@NonNullable 的组合。甚至 ? extends 就像这里类似案例中所建议的那样:https://bugs.eclipse.org/bugs/show_bug.cgi?id=507779

但警告总是只会移动而不会完全消失。

更新:

我通过使用这一行摆脱了警告:

final Set<? extends @Nullable Entry<@Nullable Integer, @Nullable String>> set = treeMap.entrySet();

但我完全不知道为什么。在我看来,我欺骗了验证器以丢失轨道或其他东西,代码真的开始变得丑陋了。

完整的新代码:

import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;

@NonNullByDefault
public class NullAnnotationTest4 {

    public static void main(String[] args) {

        final TreeMap<@Nullable Integer, @Nullable String> treeMap = new TreeMap<>();

        treeMap.put(3,  "Test1");
        treeMap.put(null, null);


        final Set<? extends @Nullable Entry<@Nullable Integer, @Nullable String>> set = treeMap.entrySet();

        for (final Iterator<? extends @Nullable Entry<@Nullable Integer, @Nullable String>> it = set.iterator(); it.hasNext(); ) {

            final Entry<@Nullable Integer, @Nullable String> entry = it.next();

            if (entry != null && entry.getKey() == null && entry.getValue() != null)
                System.out.println(entry.getKey()+" is mapped to "+entry.getValue());
        }

    }
}

更新 2矮子贴错代码了。

Set<@NonNull X>Set<@Nullable X> 等问题类型的核心是不兼容的:两者都不能分配给另一个。

也就是说:如果你有一个 Set<@NonNull X> 客户期望 提取 非空元素,并且如果集合实际上是 Set<@Nullable X> 就会中断。相反,如果你有一个 Set<@Nullable X> 客户希望能够 插入 null 到集合中,如果集合实际上是 Set<@NonNull X> 就会中断。

每当您必须处理我们知识不足的 "legacy" 类型 Set<X> 时,这些注意事项都是相关的:它可能是 Set<@NonNull X>Set<@Nullable X>.类型检查必须考虑这两种可能性(客户可能依赖于任何一种假设,因为,例如,javadoc 可能会这样说)。

通常,在 Java 中,读取与写入问题通过使用有界通配符来解决:Set<? extends X> 确保读取访问将始终产生 "at least" X(或更好)。 Set<? super X> 确保插入新元素的要求是 "at most" X,即任何 X 或更好的元素都将被接受到集合中(无论实际列表的实际要求是什么)。

要将以上内容应用于空注释,只需说 Set<? extends @Nullable X> 即可接受旧集并支持从该集读取(值至少为 @Nullable X,可能会更好,例如 @NonNull X). 如果需要插入遗留集,请将其分配给 Set<? super @NonNull X> 类型的变量。这告诉类型检查器,@NonNull X 总是足以插入。

这就是为什么 Set<? extends @Nullable Entry<..> 接受 treeMap.entrySet() 的结果,它的类型实际上是 Set<Entry<@Nullable Integer, @Nullable String>>。由于 entrySet().

的遗留签名,这里的内部类型参数完全由 treeMap 的声明注释,只有顶层类型参数 Entry 未指定

最后提到的也暗示了示例的 "real" 解决方案:使用外部注释来指示 entrySet() 实际上 returns @NonNull Set<@NonNull Entry<K,V>>。有了这个 none 的通配符魔法就需要了。