1

このコード例の警告を取り除く方法。

Java 1.8 および org.eclipse.jdt.annotation_2.1.0 で Eclipse Neon を使用しています。

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());
        }

    }
}

Update 2 Shorty が間違ったコードを貼り付けました。

4

1 に答える 1

3

Set<@NonNull X>とのような質問タイプSet<@Nullable X>は互換性がありません。どちらも他方に割り当てることはできません。

つまり、Set<@NonNull X>クライアントがnull以外の要素を抽出Set<@Nullable X>することを期待している場合、セットが実際に. 逆に、クライアントがセットに挿入Set<@Nullable X>できることを期待している場合、セットが実際に. nullSet<@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>は少なくとも レガシー セットに挿入する必要がある場合は、 type の変数に割り当てます。これは型チェッカーに、 aは常に挿入に十分であることを伝えます。@Nullable X@NonNull XSet<? super @NonNull X>@NonNull X

これが、実際には型を持つSet<? extends @Nullable Entry<..>の結果を受け入れる理由です。ここで、内部の型引数は の宣言から完全に注釈が付けられています。treeMap.entrySet()Set<Entry<@Nullable Integer, @Nullable String>>treeMapEntryentrySet()

The last mention also hints at the "real" solution for the example: use external annotations to indicate that entrySet() actually returns @NonNull Set<@NonNull Entry<K,V>>. With this none of the wildcard magic is needed.

于 2016-11-24T10:12:02.460 に答える