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

1voto

Tom Hawtin - tackline Punkte 142461

Fast jedes Problem in der Informatik kann durch Hinzufügen einer indirekten Ebene* oder Ähnlichem gelöst werden.

Führen Sie also ein nicht-generisches Objekt ein, das einer höheren Ebene angehört als ein Map . Ohne Kontext wird es nicht sehr überzeugend aussehen, aber egal:

public final class Items implements java.io.Serializable {
    private static final long serialVersionUID = 1L;
    private Map<String,String> map;
    public Items(Map<String,String> map) {
        this.map = New.immutableMap(map);
    }
    public Map<String,String> getMap() {
        return map;
    }
    @Override public String toString() {
        return map.toString();
    }
}

public final class New {
    public static <K,V> Map<K,V> immutableMap(
        Map<? extends K, ? extends V> original
    ) {
        // ... optimise as you wish...
        return Collections.unmodifiableMap(
            new HashMap<String,String>(original)
        );
    }
}

static Map<String, String> getItems(HttpSession session) {
    Items items = (Items)
        session.getAttribute("attributeKey");
    return items.getMap();
}

*Ausgenommen zu viele indirekte Ebenen.

1 Stimmen

Das Zitat wird dem verstorbenen Professor David Wheeler zugeschrieben. de.wikipedia.org/wiki/

1voto

Jim Daehn Punkte 186

Hier ist eine Möglichkeit, wie ich dies handhabe, wenn ich die equals() Betrieb.

public abstract class Section<T extends Section> extends Element<Section<T>> {
    Object attr1;

    /**
    * Compare one section object to another.
    *
    * @param obj the object being compared with this section object
    * @return true if this section and the other section are of the same
    * sub-class of section and their component fields are the same, false
    * otherwise
    */       
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            // this exists, but obj doesn't, so they can't be equal!
            return false;
        }

        // prepare to cast...
        Section<?> other;

        if (getClass() != obj.getClass()) {
            // looks like we're comparing apples to oranges
            return false;
        } else {
            // it must be safe to make that cast!
            other = (Section<?>) obj;
        }

        // and then I compare attributes between this and other
        return this.attr1.equals(other.attr1);
    }
}

Dies scheint in Java 8 zu funktionieren (sogar kompiliert mit -Xlint:unchecked )

1voto

Mark Davidson Punkte 5519

Eine schnelle Vermutung, wenn Sie Ihren Code posten kann sicher sagen, aber Sie könnten etwas entlang der Linien der getan haben

HashMap<String, Object> test = new HashMap();

was zu einer Warnung führt, wenn Sie Folgendes tun müssen

HashMap<String, Object> test = new HashMap<String, Object>();

könnte es sich lohnen, einen Blick darauf zu werfen

Generics in der Programmiersprache Java

wenn Sie nicht wissen, was zu tun ist.

1 Stimmen

Leider ist die Situation nicht so einfach. Code hinzugefügt.

1 Stimmen

Ich habe hier nach einer Antwort auf ein etwas anderes Problem gesucht: und Sie haben mir genau gesagt, was ich brauche! Danke!

0voto

mike rodent Punkte 12041

Es gibt zwei Möglichkeiten: eine, bei der die Markierung vollständig vermieden wird, und eine, bei der die Methode "frech aber nett" angewendet wird.
Das Problem sind vorgenerierte Kollektionen...
Ich glaube, die Faustregel lautet: "cast objects one thing at a time" - was das bedeutet, wenn man versucht, rohe Klassen in einer generisierten Welt zu verwenden, ist, dass, da man nicht weiß, was in dieser Map<?, ?> ist (und die JVM könnte sogar feststellen, dass es nicht einmal eine Map ist!), es offensichtlich ist, wenn man darüber nachdenkt, dass man es nicht casten kann. Wenn Sie eine Map<String, ?> map2 hätten, dann würde HashSet<String> keys = (HashSet<String>)map2.keySet() Ihnen keine Warnung geben, obwohl dies ein "Akt des Glaubens" für den Compiler ist (weil es sich als TreeSet herausstellen könnte)... aber es ist nur ein einzeln Akt des Glaubens.

PS: Auf den Einwand, dass die Iteration wie bei meiner ersten Methode "langweilig" und "zeitaufwendig" ist, lautet die Antwort "ohne Fleiß kein Preis": Eine generische Sammlung enthält garantiert nur Map.Entry<String, String>s und sonst nichts. Für diese Garantie muss man bezahlen. Bei der systematischen Verwendung von Generika erfolgt diese Zahlung in Form der Einhaltung von Codierungsvorschriften und nicht in Form von Maschinenzeit!
Eine Denkweise besagt, dass Sie die Einstellungen von Eclipse so einstellen sollten, dass solche nicht angekreuzten Würfe als Fehler und nicht als Warnungen angezeigt werden. In diesem Fall müssten Sie meine erste Methode anwenden.

package scratchpad;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;

public class YellowMouse {

    // First way

    Map<String, String> getHashMapStudiouslyAvoidingSuppressTag(HttpSession session) {
      Map<?, ?> theHash = (Map<?, ?>)session.getAttribute("attributeKey");

      Map<String, String> yellowMouse = new HashMap<String, String>();
      for( Map.Entry<?, ?> entry : theHash.entrySet() ){
        yellowMouse.put( (String)entry.getKey(), (String)entry.getValue() );
      }

      return yellowMouse;
    }

    // Second way

    Map<String, String> getHashMapUsingNaughtyButNiceUtilityMethod(HttpSession session) {
      return uncheckedCast( session.getAttribute("attributeKey") );
    }

    // NB this is a utility method which should be kept in your utility library. If you do that it will
    // be the *only* time in your entire life that you will have to use this particular tag!!

    @SuppressWarnings({ "unchecked" })
    public static synchronized <T> T uncheckedCast(Object obj) {
        return (T) obj;
    }

}

0 Stimmen

Die Tatsache, dass Sie keine Kommentarrechte haben, erlaubt es Ihnen nicht, die Antworten anderer zu bearbeiten, um Ihre Kommentare hinzuzufügen; Sie bearbeiten die Antworten anderer, um sie in Bezug auf Formatierung, Syntax, ... zu verbessern, nicht um Ihre Meinung dazu hinzuzufügen. Wenn Sie 50 Repräsentanten erreicht haben, werden Sie überall kommentieren können. In der Zwischenzeit bin ich mir sicher, dass Sie widerstehen können (oder, wenn Sie es wirklich nicht können, schreiben Sie Ihre Kommentare zu bestehenden Antworten in Ihrem Beitrag). (Anmerkung für andere: Ich schreibe das, weil ich seine vorgeschlagenen Kommentar-Edits zu anderen Beiträgen in den Moderations-Tools gesehen - und abgelehnt - habe)

0voto

Luke 10X Punkte 878

Wenn Sie sicher sind, dass der von session.getAttribute() zurückgegebene Typ HashMap ist, können Sie nicht genau auf diesen Typ typisieren, sondern sich nur auf die Überprüfung der allgemeinen HashMap verlassen

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

Eclipse wird dann überraschend Warnungen ausgeben, aber das kann natürlich zu Laufzeitfehlern führen, die schwer zu beheben sind. Ich verwende diesen Ansatz nur in nicht betriebskritischen Kontexten.

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