如何摆脱"空型安全"在Treeclipse的eclipse neon中发出警告

时间:2016-11-22 14:11:32

标签: java eclipse non-nullable java-annotations

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

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

1 个答案:

答案 0 :(得分:1)

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

即使:如果您有Set<@NonNull X>个客户希望提取非空元素,并且如果该集合实际为Set<@Nullable X>则会中断。相反,如果您有Set<@Nullable X>个客户希望能够插入 null到集合中,并且如果该集合实际上是Set<@NonNull X>则会中断。

只要您需要处理我们缺乏足够知识的“遗留”类型Set<X>,这些注意事项就相关:它可能是Set<@NonNull X>Set<@Nullable X>。类型检查必须考虑两种可能性(客户可能依赖于任一假设,因为例如,javadoc可以这样说)。

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

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

这就是@NonNull X接受Set<? extends @Nullable Entry<..>的结果的原因,treeMap.entrySet()实际上具有Set<Entry<@Nullable Integer, @Nullable String>>类型。这里的内部类型参数完全由treeMap的声明注释,由于Entry的遗留签名,只有顶级类型参数entrySet()未指定。

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