692 Stimmen

Wie gehe ich mit ungeprüften Besetzungswarnungen um?

Eclipse gibt mir eine Warnung der folgenden Form:

Typ Sicherheit: Ungeprüfter Cast von Object nach HashMap

Dies stammt aus einem Aufruf an eine API, über die ich keine Kontrolle habe und die Object zurückgibt:

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

Ich möchte Eclipse-Warnungen nach Möglichkeit vermeiden, da sie theoretisch zumindest auf ein potenzielles Codeproblem hinweisen. Ich habe allerdings noch keine gute Möglichkeit gefunden, dieses Problem zu beseitigen. Ich kann die einzelne betroffene Zeile in eine eigene Methode auslagern und Folgendes hinzufügen @SuppressWarnings("unchecked") zu dieser Methode, wodurch die Auswirkungen eines Codeblocks, in dem ich Warnungen ignoriere, begrenzt werden. Gibt es bessere Möglichkeiten? Ich möchte diese Warnungen in Eclipse nicht ausschalten.

Bevor ich zu dem Code kam, war es einfacher, aber es gab trotzdem Warnungen:

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

Das Problem war, dass an anderer Stelle, wenn man versuchte, den Hash zu verwenden, Warnungen angezeigt wurden:

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.

0 Stimmen

Wenn Sie HttpSession auf diese Weise verwenden, lesen Sie den Artikel von Brian Goetz zu diesem Thema: ibm.com/developerworks/library/j-jtp09238.html

0 Stimmen

Wenn ein ungeprüfter Cast unvermeidbar ist, ist es eine gute Idee, ihn mit etwas zu koppeln, das seinen Typ logisch repräsentiert (wie ein enum oder sogar Instanzen von Class<T> ), so dass Sie einen Blick darauf werfen können und savoir es ist sicher.

4 Stimmen

8voto

Gonen I Punkte 4891

Die Utility-Funktion Objects.Unchecked in der obigen Antwort von Esko Luontola ist eine großartige Möglichkeit, um Programmunordnung zu vermeiden.

Wenn Sie die SuppressWarnings nicht auf eine ganze Methode anwenden wollen, zwingt Java Sie dazu, sie auf eine lokale Methode anzuwenden. Wenn Sie einen Cast für ein Mitglied benötigen, kann dies zu Code wie diesem führen:

@SuppressWarnings("unchecked")
Vector<String> watchedSymbolsClone = (Vector<String>) watchedSymbols.clone();
this.watchedSymbols = watchedSymbolsClone;

Die Verwendung des Dienstprogramms ist viel sauberer, und es ist immer noch offensichtlich, was Sie tun:

this.watchedSymbols = Objects.uncheckedCast(watchedSymbols.clone());

HINWEIS: Ich halte es für wichtig, hinzuzufügen, dass die Warnung manchmal wirklich bedeutet, dass Sie etwas falsch machen:

ArrayList<Integer> intList = new ArrayList<Integer>();
intList.add(1);
Object intListObject = intList; 

 // this line gives an unchecked warning - but no runtime error
ArrayList<String> stringList  = (ArrayList<String>) intListObject;
System.out.println(stringList.get(0)); // cast exception will be given here

Der Compiler teilt Ihnen mit, dass dieser Cast zur Laufzeit NICHT überprüft wird, so dass kein Laufzeitfehler ausgelöst wird, bis Sie versuchen, auf die Daten im generischen Container zuzugreifen.

6voto

abbas Punkte 5423

Die Unterdrückung von Warnungen ist keine Lösung. Sie sollten nicht zwei Ebenen in einer Anweisung abbilden.

HashMap<String, String> getItems(javax.servlet.http.HttpSession session) {

    // first, cast the returned Object to generic HashMap<?,?>
    HashMap<?, ?> theHash = (HashMap<?, ?>)session.getAttribute("attributeKey");

    // next, cast every entry of the HashMap to the required type <String, String>
    HashMap<String, String> returingHash = new HashMap<>();
    for (Entry<?, ?> entry : theHash.entrySet()) {
        returingHash.put((String) entry.getKey(), (String) entry.getValue());
    }
    return returingHash;
}

1 Stimmen

Seine fünf Jahre alte Frage? Müssen Sie so viel Arbeit machen? Da Java über Type Erasure verfügt, sollte die zweite Hashmap zur Laufzeit mit der ersten identisch sein; ich denke, es wäre effizienter und würde die Kopie vermeiden, wenn Sie einfach durch die Einträge iterieren und überprüfen, ob sie alle Instanzen von Strings sind. Oder, TBH, inspizieren Sie die Quelle des Servlet-JAR Sie verwenden und überprüfen Sie es nur immer Strings setzt.

1 Stimmen

Bis zum heutigen Tag sehe ich diese Warnung in Projekten. Sein Problem war nicht die Überprüfung des Typs, sondern eine Warnung, die durch ein "put" in eine nicht gecastete Karte verursacht wurde.

2voto

phihag Punkte 261131

Vielleicht habe ich die Frage missverstanden (ein Beispiel und ein paar Zeilen dazu wären nett), aber warum verwenden Sie nicht immer eine geeignete Schnittstelle (und Java5+)? Ich sehe keinen Grund, warum man jemals ein Casting auf eine HashMap anstelle einer Map<KeyType,ValueType> . In der Tat kann ich mir nicht vorstellen jede Grund, den Typ einer Variablen auf HashMap anstelle von Map .

Und warum ist die Quelle ein Object ? Handelt es sich um einen Parametertyp einer Legacy-Sammlung? Wenn ja, verwenden Sie Generika und geben Sie den gewünschten Typ an.

2 Stimmen

Ich bin mir ziemlich sicher, dass der Wechsel zu Map in diesem Fall nichts ändern würde, aber danke für den Programmiertipp, der meine Arbeitsweise vielleicht zum Besseren wendet. Die Quelle des Objekts ist eine API, über die ich keine Kontrolle habe (Code hinzugefügt).

2voto

jfreundo Punkte 61

Nehmen Sie diese, es ist viel schneller als die Erstellung einer neuen HashMap, wenn es bereits eine ist, aber immer noch sicher, da jedes Element gegen seinen Typ geprüft wird...

@SuppressWarnings("unchecked")
public static <K, V> HashMap<K, V> toHashMap(Object input, Class<K> key, Class<V> value) {
       assert input instanceof Map : input;

       for (Map.Entry<?, ?> e : ((HashMap<?, ?>) input).entrySet()) {
           assert key.isAssignableFrom(e.getKey().getClass()) : "Map contains invalid keys";
           assert value.isAssignableFrom(e.getValue().getClass()) : "Map contains invalid values";
       }

       if (input instanceof HashMap)
           return (HashMap<K, V>) input;
       return new HashMap<K, V>((Map<K, V>) input);
    }

0 Stimmen

key.isAssignableFrom(e.getKey().getClass()) kann geschrieben werden als key.isInstance(e.getKey())

2voto

Fortyrunner Punkte 12559

Wenn ich eine API verwenden muss, die keine Generics unterstützt,. Ich versuche, diese Aufrufe in Wrapper-Routinen mit so wenigen Zeilen wie möglich zu isolieren. Ich verwende dann die SuppressWarnings-Annotation und füge gleichzeitig die Typsicherheits-Casts hinzu.

Dies ist nur eine persönliche Vorliebe, um die Dinge so ordentlich wie möglich zu halten.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X