2016-11-22 3 views
0

Comment se débarrasser de l'avertissement dans cet exemple de code.Comment se débarrasser de l'avertissement "Sécurité de type Null" dans eclipse neon pour TreeMap

J'utilise Eclipse Neon avec Java 1.8 et 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()); 
     } 

    } 
} 

L'avertissement est:

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

J'ai essayé plusieurs combinaisons de @Nullable et @ NonNullable Même ? extends comme cela a été suggéré dans un cas similaire ici: https://bugs.eclipse.org/bugs/show_bug.cgi?id=507779

Mais l'avertissement se déplace toujours mais ne disparaît jamais complètement.

Mise à jour:

je me suis débarrassé de l'avertissement en utilisant cette ligne:

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

Mais je suis totalement perdu au pourquoi. Il me semble que je trompe le validateur en perdant la piste ou quelque chose et le code commence vraiment à devenir moche.

nouveau code complet:

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 collé le mauvais code.

+0

La variable 'set' ne devrait-elle pas être juste Set >'? Les entrées de l'ensemble d'entrées ne devraient probablement jamais être nulles. –

+0

J'ai essayé cela en premier. Mais alors l'erreur est qu'il ne peut pas convertir 'Set Torge

Répondre

1

Au cœur des types de questions comme Set<@NonNull X> et Set<@Nullable X> sont incompatibles: aucun n'est assignable à l'autre.

À savoir: si vous avez un Set<@NonNull X> clients attendent à extrait éléments non nuls et se cassent si l'ensemble est en fait Set<@Nullable X>. Inversement, si vous avez un Set<@Nullable X> clients s'attendent à pouvoir insérernull dans l'ensemble et cassera si l'ensemble est réellement Set<@NonNull X>. Ces considérations sont pertinentes chaque fois que vous devez traiter avec un type «legacy» Set<X> lorsque nous n'avons pas suffisamment de connaissances: il peut être conçu comme Set<@NonNull X> ou comme Set<@Nullable X>. La vérification de type doit prendre en compte les deux possibilités (les clients peuvent se fonder sur l'une ou l'autre des hypothèses car, par exemple, le javadoc peut le dire).

Généralement, en Java, le problème de lecture et d'écriture est résolu en utilisant des caractères génériques délimités: Set<? extends X> garantit que l'accès en lecture produira toujours "au moins" X (ou mieux). Set<? super X> garantit que l'exigence d'insertion de nouveaux éléments est "au plus" X, c'est-à-dire que tout X ou mieux sera accepté dans l'ensemble (quelles que soient les exigences réelles de la liste actuelle).

Pour appliquer ce qui précède null annotations simplement dire Set<? extends @Nullable X> d'accepter un ensemble existant et support de lecture de l'ensemble (valeurs seront au moins @Nullable X, pourrait être mieux, par exemple, @NonNull X). Si vous devez insérer dans un ensemble hérité, affectez-le à une variable de type Set<? super @NonNull X>. Cela indique au vérificateur de type qu'un @NonNull X sera toujours assez bon pour l'insertion.C'est pourquoi Set<? extends @Nullable Entry<..> accepte le résultat de treeMap.entrySet(), qui a en fait le type Set<Entry<@Nullable Integer, @Nullable String>>. Ici les arguments de type interne sont entièrement annotés à partir de la déclaration treeMap, seul l'argument de type toplevel Entry est non spécifié, en raison de la signature héritée de entrySet().

La dernière mention fait également allusion à la solution «réelle» pour l'exemple: utiliser des annotations externes pour indiquer que entrySet() renvoie effectivement @NonNull Set<@NonNull Entry<K,V>>. Avec cela, aucune magie générique n'est nécessaire.