650 votes

Comment traiter les avertissements de cast décochée ?

Eclipse est de me donner un avertissement de la forme suivante:

Type safety: Unchecked cast from Object to HashMap<String, String>

C'est à partir d'un appel à une API que je n'ai aucun contrôle sur ce qui renvoie l'Objet:

HashMap<String, String> getItems(javax.servlet.http.HttpSession session) {
  HashMap<String, String> theHash = (HashMap<String, String>)session.getAttribute("attributeKey");
  return theHash;
}

Je voudrais éviter de l'Éclipse mises en garde, si possible, puisque théoriquement, ils indiquent au moins un potentiel problème de code. Je n'ai pas trouvé un bon moyen d'éliminer celui-ci encore, cependant. Je peux extraire de la seule ligne participent à une méthode par lui-même et ajouter @SuppressWarnings("unchecked") à cette méthode, ce qui limite l'impact d'avoir un bloc de code dans lequel je ignorer les avertissements. Toutes les meilleures options? Je ne veux pas faire ces avertissements dans Eclipse.

Avant que je suis venu pour le code, il est plus simple, mais toujours provoqué des avertissements:

HashMap getItems(javax.servlet.http.HttpSession session) {
  HashMap theHash = (HashMap)session.getAttribute("attributeKey");
  return theHash;
}

Le problème était ailleurs, lorsque vous avez essayé d'utiliser la table de hachage, vous obtiendrez des avertissements:

HashMap items = getItems(session);
items.put("this", "that");

Type safety: The method put(Object, Object) belongs to the raw type HashMap.  References to generic type HashMap<K,V> should be parameterized.

585voto

Michael Myers Points 82361

La réponse la plus évidente, bien sûr, est de ne pas faire la décoché exprimés.

Si c'est absolument nécessaire, alors au moins essayer de limiter la portée de l' @SuppressWarnings d'annotation. Conformément à sa documentation Javadoc, il peut aller sur les variables locales; de cette façon, il n'a même pas d'incidence sur l'ensemble de la méthode.

Exemple:

@SuppressWarnings("unchecked")
Map<String, String> myMap = (Map<String, String>) deserializeMap();

Il n'y a aucun moyen de déterminer si l' Map devrait vraiment avoir les paramètres génériques <String, String>. Vous devez savoir à l'avance ce que les paramètres doivent être (ou vous vous trouvez quand vous obtenez un ClassCastException). C'est pourquoi le code génère un avertissement, parce que le compilateur ne peut pas savoir si est sûr.

181voto

Julien Chastang Points 8357

Malheureusement, il n'y a pas de grandes options ici. Rappelez-vous, le but de tout cela est de préserver la sécurité de type. "Java Génériques" propose, des solutions de traitement de la non-généricisés héritage des bibliothèques, et il y en a un en particulier a appelé le "vide boucle technique" dans la section 8.2. En gros, faire de l'insécurité en fonte, et de supprimer l'avertissement. Puis la boucle à travers la carte comme ceci:

    @SuppressWarnings("unchecked")
    Map<String,Number> map = getMap();
    for (String  s : map.keySet());
    for (Number  n : map.values());

Si un type inattendu est détectée, vous obtiendrez un runtime ClassCastException, mais au moins il va se passer près de la source du problème.

alt text

115voto

skiphoppy Points 16563

Wow, je crois que j'ai trouvé la réponse à ma propre question. Je ne suis pas sûr que ça en vaut la peine! :)

Le problème, c'est que le cast n'est pas cochée. Donc, vous devez vérifier vous-même. Vous ne pouvez pas il suffit de cocher un type paramétré avec instanceof, parce que le paramétrée type d'information n'est pas disponible au moment de l'exécution, après avoir été effacé au moment de la compilation.

Mais, vous pouvez effectuer une vérification de chaque élément dans la table de hachage, avec instanceof, et en faisant cela, vous pouvez construire une nouvelle table de hachage qui est de type sécurisé. Et vous ne les provoque pas de mises en garde.

Grâce à mmyers et Esko Luontola, j'ai paramétré le code que j'ai initialement écrit ici, de sorte qu'il peut être enveloppé dans une classe utilitaire quelque part et utilisé pour tout paramétré HashMap. Si vous voulez comprendre mieux et ne sont pas très familiers avec les génériques, j'encourage la visualisation de l'historique de l'édition de cette réponse.

public static <K, V> HashMap<K, V> castHash(HashMap input,
                                            Class<K> keyClass,
                                            Class<V> valueClass) {
  HashMap<K, V> output = new HashMap<K, V>();
  if (input == null)
      return output;
  for (Object key: input.keySet().toArray()) {
    if ((key == null) || (keyClass.isAssignableFrom(key.getClass()))) {
        Object value = input.get(key);
        if ((value == null) || (valueClass.isAssignableFrom(value.getClass()))) {
            K k = keyClass.cast(key);
            V v = valueClass.cast(value);
            output.put(k, v);
        } else {
            throw new AssertionError(
                "Cannot cast to HashMap<"+ keyClass.getSimpleName()
                +", "+ valueClass.getSimpleName() +">"
                +", value "+ value +" is not a "+ valueClass.getSimpleName()
            );
        }
    } else {
        throw new AssertionError(
            "Cannot cast to HashMap<"+ keyClass.getSimpleName()
            +", "+ valueClass.getSimpleName() +">"
            +", key "+ key +" is not a " + keyClass.getSimpleName()
        );
    }
  }
  return output;
}

C'est beaucoup de travail, peut-être pour peu de résultats... je ne sais pas si je vais l'utiliser ou pas. Je te remercie de tout commentaire quant à savoir si les gens pensent qu'il vaut le coup ou pas. Aussi, je vous en serais reconnaissant suggestions d'amélioration: est-il quelque chose de mieux, je peux faire en plus de jeter AssertionErrors? Est-il quelque chose de mieux je pourrais jeter? Devrais-je le faire un checked Exception?

52voto

Dave Points 2870

Dans les préférences d’Eclipse, allez dans Java -> compilateur -> les erreurs/avertissements-> types génériques et vérifier la `` case à cocher.

Cela répond à l’intention de la question, c'est-à-dire

Je voudrais éviter les avertissements d’Eclipse...

Si ce n’est pas l’esprit.

23voto

Dustin Getz Points 8514

Ce genre de choses est difficile, mais voici mes réflexions:

Si votre API renvoie l'Objet, alors il n'y a rien que vous pouvez faire, peu importe ce que, vous serez à l'aveuglette moulage de l'objet. Vous laissez Java jeter ClassCastExceptions, ou vous pouvez vérifier chaque élément de vous-même et de lancer des Affirmations ou IllegalArgumentExceptions ou quelque chose comme ça, mais ces runtime contrôles sont toutes équivalentes. Vous devez supprimer le moment de la compilation décoché cast peu importe ce que vous faites au moment de l'exécution.

J'avais juste préfèrent les aveugles de fonte et de laisser la machine effectuer à son moment de l'exécution pour moi depuis que nous "savons" que l'API de retour, et sont généralement disposés à assumer que l'API travaille. Utiliser des génériques partout au-dessus de la fonte, si vous en avez besoin. Vous n'avez pas vraiment acheter quelque chose depuis, vous avez toujours le seul à l'aveugle en fonte, mais au moins, vous pouvez utiliser des génériques à partir de là, et la JVM peut vous aider à éviter aveugle jette dans les autres pièces de votre code.

Dans ce cas particulier, sans doute, vous pouvez voir l'appel à SetAttribute et de voir le type va, donc il suffit d'aveugles-casting le type de même avant de sortir, n'est pas immoral. Ajouter un commentaire référencement de la SetAttribute et être fait avec elle.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X