1

如何摆脱此示例代码中的警告。

我将 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 Shorty 粘贴了错误的代码。

4

1 回答 1

3

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

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

每当您必须处理Set<X>我们知识不足的“遗留”类型时,这些考虑因素都是相关的:它可能旨在作为 aSet<@NonNull X>或 as Set<@Nullable X>。类型检查必须考虑这两种可能性(客户可能依赖于任何一种假设,因为例如 javadoc 可以这样说)。

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

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

这就是为什么Set<? extends @Nullable Entry<..>接受treeMap.entrySet()实际具有类型的结果的原因Set<Entry<@Nullable Integer, @Nullable String>>。这里内部类型参数完全从 的声明中注释treeMap,只有顶级类型参数Entry未指定,因为entrySet().

最后提到的还暗示了该示例的“真实”解决方案:使用外部注释来指示entrySet()实际返回@NonNull Set<@NonNull Entry<K,V>>. 有了这个,就不需要通配符魔法了。

于 2016-11-24T10:12:02.460 回答