Was ist SuppressWarnings ("nicht markiert") in Java?

443

Manchmal sehe ich beim Durchsuchen von Code, dass viele Methoden eine Anmerkung angeben:

@SuppressWarnings("unchecked")

Was bedeutet das?

Jojo
quelle

Antworten:

420

Manchmal Java Generics einfach nicht lassen Sie das tun , was Sie wollen, und Sie brauchen , um effektiv den Compiler zu sagen , dass das, was Sie tun wirklich wird zur Ausführungszeit legal.

Normalerweise empfinde ich dies als Schmerz, wenn ich mich über eine generische Benutzeroberfläche lustig mache, aber es gibt auch andere Beispiele. Es ist in der Regel lohnt sich, einen Weg zur Vermeidung der Warnung zu arbeiten , versuchen , anstatt zu unterdrücken sie (die Java Generics FAQ hilft hier) , aber manchmal auch wenn es ist möglich, es beugt sich den Code aus der Form so sehr , dass die Warnung ordentlicheres ist unterdrückt wird . Fügen Sie in diesem Fall immer einen erklärenden Kommentar hinzu!

Dieselben häufig gestellten Fragen zu Generika enthalten mehrere Abschnitte zu diesem Thema, beginnend mit "Was ist eine" deaktivierte "Warnung?" - Es ist eine Lektüre wert.

Jon Skeet
quelle
10
In einigen Fällen können Sie dies vermeiden, indem Sie YourClazz.class.cast () verwenden. Funktioniert für einzelne generische Elementcontainer, jedoch nicht für Sammlungen.
Akarnokd
Oder verwenden Sie vorzugsweise Wildcard-Generika (YourClazz<?>)- Java warnt niemals vor solchen Casts, da diese sicher sind. Dies funktioniert jedoch nicht immer (Details finden Sie in den häufig gestellten Fragen zu Generika).
Konrad Borowski
48

Es ist eine Anmerkung, um Kompilierungswarnungen über nicht aktivierte generische Operationen (keine Ausnahmen) wie Casts zu unterdrücken. Dies impliziert im Wesentlichen, dass der Programmierer nicht über diese informiert werden wollte, die ihm bereits beim Kompilieren eines bestimmten Codebits bekannt sind.

Weitere Informationen zu dieser speziellen Anmerkung finden Sie hier:

SuppressWarnings

Darüber hinaus bietet Oracle hier eine Tutorial-Dokumentation zur Verwendung von Anmerkungen:

Anmerkungen

Wie sie es ausdrückten,

"Die 'ungeprüfte' Warnung kann auftreten, wenn eine Schnittstelle zu Legacy-Code hergestellt wird, der vor dem Aufkommen von Generika geschrieben wurde (siehe Lektion" Generika ")."

Dreadwail
quelle
19

Dies kann auch bedeuten, dass die aktuelle Java-Systemversion für Ihren Fall nicht gut genug ist. Es gab mehrere JSR-Vorschläge / Hacks, um dies zu beheben: Typ-Token, Super-Typ-Token , Class.cast ().

Wenn Sie diese Unterdrückung wirklich brauchen, schränken Sie sie so weit wie möglich ein (z. B. setzen Sie sie nicht auf die Klasse selbst oder auf eine lange Methode). Ein Beispiel:

public List<String> getALegacyListReversed() {
   @SuppressWarnings("unchecked") List<String> list =
       (List<String>)legacyLibrary.getStringList();

   Collections.reverse(list);
   return list;
}
akarnokd
quelle
10

Die SuppressWarning- Annotation wird verwendet, um Compiler-Warnungen für das annotierte Element zu unterdrücken. Insbesondere uncheckedermöglicht die Kategorie die Unterdrückung von Compiler-Warnungen, die als Ergebnis ungeprüfter Typumwandlungen generiert werden.

Brandon E Taylor
quelle
Ihr SupressWarning-Link ist tot. Hier ist eine Alternative: docs.oracle.com/javase/specs/jls/se6/html/…
James Daily
8

Einfach: Es ist eine Warnung, mit der der Compiler angibt, dass er die Typensicherheit nicht gewährleisten kann.

JPA-Servicemethode zum Beispiel:

@SuppressWarnings("unchecked")
public List<User> findAllUsers(){
    Query query = entitymanager.createQuery("SELECT u FROM User u");
    return (List<User>)query.getResultList();
}

Wenn ich die @ SuppressWarnings ("nicht markiert") hier nicht kommentiert hätte, hätte es ein Problem mit der Zeile, in der ich meine Ergebnisliste zurückgeben möchte.

In Verknüpfung bedeutet Typensicherheit: Ein Programm gilt als typsicher, wenn es ohne Fehler und Warnungen kompiliert wird und zur Laufzeit keine unerwarteten ClassCastException s auslöst.

Ich baue auf http://www.angelikalanger.com/GenericsFAQ/FAQSections/Fundamentals.html auf

Daniel Perník
quelle
2
Dies ist ein gutes Beispiel für die Situation, in der SuppressWarnings verwendet werden muss.
Jimmy
8

In Java werden Generika durch Löschen von Typen implementiert. Zum Beispiel der folgende Code.

List<String> hello = List.of("a", "b");
String example = hello.get(0);

Wird wie folgt kompiliert.

List hello = List.of("a", "b");
String example = (String) hello.get(0);

Und List.ofist definiert als.

static <E> List<E> of(E e1, E e2);

Was nach dem Löschen des Typs wird.

static List of(Object e1, Object e2);

Der Compiler hat keine Ahnung, was zur Laufzeit generische Typen sind. Wenn Sie also so etwas schreiben.

Object list = List.of("a", "b");
List<Integer> actualList = (List<Integer>) list;

Java Virtual Machine hat keine Ahnung, welche generischen Typen beim Ausführen eines Programms vorhanden sind. Daher wird diese kompiliert und ausgeführt. Bei Java Virtual Machine handelt es sich um eine ListTypumwandlung (dies ist das einzige, was überprüft werden kann, sodass nur das überprüft wird).

Aber jetzt füge diese Zeile hinzu.

Integer hello = actualList.get(0);

Und JVM wird ein Unerwartetes auslösen ClassCastException, da der Java-Compiler eine implizite Umwandlung eingefügt hat.

java.lang.ClassCastException: java.base/java.lang.String cannot be cast to java.base/java.lang.Integer

Eine uncheckedWarnung teilt einem Programmierer mit, dass eine Besetzung dazu führen kann, dass ein Programm eine Ausnahme an einer anderen Stelle auslöst. Das Unterdrücken der Warnung mit @SuppressWarnings("unchecked")teilt dem Compiler mit, dass der Programmierer den Code für sicher hält und keine unerwarteten Ausnahmen verursacht.

Warum willst du das tun? Das Java-Typsystem ist nicht gut genug, um alle möglichen Typverwendungsmuster darzustellen. Manchmal wissen Sie vielleicht, dass eine Besetzung sicher ist, aber Java bietet keine Möglichkeit, dies zu sagen - um Warnungen wie diese auszublenden, @SupressWarnings("unchecked")kann sie verwendet werden, damit sich ein Programmierer auf echte Warnungen konzentrieren kann. Gibt beispielsweise Optional.empty()einen Singleton zurück, um die Zuweisung leerer Optionen zu vermeiden, in denen kein Wert gespeichert ist.

private static final Optional<?> EMPTY = new Optional<>();
public static<T> Optional<T> empty() {
    @SuppressWarnings("unchecked")
    Optional<T> t = (Optional<T>) EMPTY;
    return t;
}

Diese Umwandlung ist sicher, da der in einer leeren Option gespeicherte Wert nicht abgerufen werden kann, sodass kein Risiko für unerwartete Klassenbesetzungsausnahmen besteht.

Konrad Borowski
quelle
5

Sie können die Compiler-Warnungen unterdrücken und den Generika mitteilen, dass der von Ihnen geschriebene Code dementsprechend legal ist.

Beispiel:

@SuppressWarnings("unchecked")
public List<ReservationMealPlan> retreiveMealPlan() {
     List<ReservationMealPlan> list=new ArrayList<ReservationMealPlan>();
    TestMenuService testMenuService=new TestMenuService(em, this.selectedInstance);
    list = testMenuService.getMeal(reservationMealPlan);
    return list;
 }
sksumaprakash
quelle
5

Ein Trick besteht darin, eine Schnittstelle zu erstellen, die eine generische Basisschnittstelle erweitert ...

public interface LoadFutures extends Map<UUID, Future<LoadResult>> {}

Dann können Sie es mit instanceof vor der Besetzung überprüfen ...

Object obj = context.getAttribute(FUTURES);
if (!(obj instanceof LoadFutures)) {
    String format = "Servlet context attribute \"%s\" is not of type "
            + "LoadFutures. Its type is %s.";
    String msg = String.format(format, FUTURES, obj.getClass());
    throw new RuntimeException(msg);
}
return (LoadFutures) obj;
Brian Edwards
quelle
4

Soweit ich weiß, hat es vorerst damit zu tun, Warnungen vor Generika zu unterdrücken. Generika sind ein neues Programmierkonstrukt, das in früheren JDK-Versionen als JDK 5 nicht unterstützt wird. Daher kann jede Mischung der alten Konstrukte mit den neuen zu unerwarteten Ergebnissen führen.

Der Compiler warnt den Programmierer davor, aber wenn der Programmierer es bereits weiß, kann er diese gefürchteten Warnungen mit SuppressWarnings deaktivieren.

BakerTheHacker
quelle
1
JDK5 ist neu? Es hat den größten Teil seiner Lebensdauer abgelaufen.
Tom Hawtin - Tackline
Ich weiß, dass JDK 5 ziemlich veraltet ist. Ich meinte damit, dass es in dem Sinne neu ist, dass es neue Funktionen in Java eingeführt hat, die zuvor in JDK 4 nicht angeboten wurden. Beachten Sie auch, dass dort diejenigen noch auf JDK 7 warten, bevor sie JDK 5 hinter sich lassen Um JDK 6 anzunehmen, kann ich nicht begründen warum!
BakerTheHacker
2

Eine Warnung, mit der der Compiler angibt, dass er die Typensicherheit nicht gewährleisten kann. Der Begriff "ungeprüfte" Warnung ist irreführend. Dies bedeutet nicht, dass die Warnung in keiner Weise deaktiviert ist. Der Begriff "nicht markiert" bezieht sich auf die Tatsache, dass der Compiler und das Laufzeitsystem nicht über genügend Typinformationen verfügen, um alle Typprüfungen durchzuführen, die zur Gewährleistung der Typensicherheit erforderlich wären. In diesem Sinne sind bestimmte Operationen "deaktiviert".

Die häufigste Quelle für "ungeprüfte" Warnungen ist die Verwendung von Rohtypen. "ungeprüfte" Warnungen werden ausgegeben, wenn auf ein Objekt über eine Rohtypvariable zugegriffen wird, da der Rohtyp nicht genügend Typinformationen bereitstellt, um alle erforderlichen Typprüfungen durchzuführen.

Beispiel (einer ungeprüften Warnung in Verbindung mit Rohtypen):

TreeSet set = new TreeSet(); 
set.add("abc");        // unchecked warning 
set.remove("abc");
warning: [unchecked] unchecked call to add(E) as a member of the raw type java.util.TreeSet 
               set.add("abc");  
                      ^

Wenn die add-Methode aufgerufen wird, weiß der Compiler nicht, ob es sicher ist, der Auflistung ein String-Objekt hinzuzufügen. Wenn das TreeSet eine Sammlung ist, die String s (oder einen Supertyp davon) enthält, ist es sicher. Anhand der vom Rohtyp TreeSet bereitgestellten Typinformationen kann der Compiler dies jedoch nicht erkennen. Daher ist der Anruf möglicherweise unsicher und es wird eine "ungeprüfte" Warnung ausgegeben.

"ungeprüfte" Warnungen werden auch gemeldet, wenn der Compiler eine Umwandlung findet, deren Zieltyp entweder ein parametrisierter Typ oder ein Typparameter ist.

Beispiel (einer ungeprüften Warnung in Verbindung mit einer Umwandlung in einen parametrisierten Typ oder eine Typvariable):

  class Wrapper<T> { 
  private T wrapped ; 
  public Wrapper (T arg) {wrapped = arg;} 
  ... 
  public Wrapper <T> clone() { 
    Wrapper<T> clon = null; 
     try {  
       clon = (Wrapper<T>) super.clone(); // unchecked warning 
     } catch (CloneNotSupportedException e) {  
       throw new InternalError();  
     } 
     try {  
       Class<?> clzz = this.wrapped.getClass(); 
       Method   meth = clzz.getMethod("clone", new Class[0]); 
       Object   dupl = meth.invoke(this.wrapped, new Object[0]); 
       clon.wrapped = (T) dupl; // unchecked warning 
     } catch (Exception e) {} 
     return clon; 
  } 
} 
warning: [unchecked] unchecked cast 
found   : java.lang.Object 
required: Wrapper <T> 
                  clon = ( Wrapper <T>)super.clone();  
                                                ^ 
warning: [unchecked] unchecked cast 
found   : java.lang.Object 
required: T 
                  clon. wrapped = (T)dupl;

Eine Umwandlung, deren Zieltyp entweder ein (konkreter oder begrenzter Platzhalter) parametrisierter Typ oder ein Typparameter ist, ist unsicher, wenn eine dynamische Typprüfung zur Laufzeit beteiligt ist. Zur Laufzeit ist nur der Typlöschvorgang verfügbar, nicht der genaue statische Typ, der im Quellcode sichtbar ist. Infolgedessen wird der Laufzeitteil der Umwandlung basierend auf dem Löschen des Typs und nicht auf dem genauen statischen Typ ausgeführt.

In diesem Beispiel würde die Umwandlung in Wrapper prüfen, ob das von super.clone zurückgegebene Objekt ein Wrapper ist, nicht, ob es sich um einen Wrapper mit einem bestimmten Elementtyp handelt. In ähnlicher Weise werden die Umwandlungen in den Typparameter T zur Laufzeit in den Typ Object umgewandelt und wahrscheinlich insgesamt optimiert. Aufgrund der Typlöschung kann das Laufzeitsystem zur Laufzeit keine nützlicheren Typprüfungen durchführen.

In gewisser Weise ist der Quellcode irreführend, da er darauf hindeutet, dass eine Umwandlung in den jeweiligen Zieltyp durchgeführt wird, während der dynamische Teil der Umwandlung nur gegen die Typlöschung des Zieltyps prüft. Die Warnung "nicht markiert" wird ausgegeben, um den Programmierer auf diese Nichtübereinstimmung zwischen dem statischen und dem dynamischen Aspekt der Besetzung aufmerksam zu machen.

Bitte beachten Sie: Was ist eine "ungeprüfte" Warnung?

Raghu K Nair
quelle
2

Die @ SuppressWarnings-Annotation ist eine der drei integrierten Annotationen, die in JDK verfügbar sind und neben @Override und @Deprecated in Java 1.5 hinzugefügt wurden.

@SuppressWarnings weist den Compiler an, die angegebene Compiler-Warnung im mit Anmerkungen versehenen Element und alle Programmelemente in diesem Element zu ignorieren oder zu unterdrücken. Wenn beispielsweise eine Klasse mit Anmerkungen versehen ist, um eine bestimmte Warnung zu unterdrücken, wird auch eine Warnung getrennt, die in einer Methode innerhalb dieser Klasse generiert wurde.

Möglicherweise haben Sie @SuppressWarnings ("nicht markiert") und @SuppressWarnings ("seriell") gesehen, zwei der beliebtesten Beispiele für @ SuppressWarnings-Anmerkungen. Ersteres wird verwendet, um Warnungen zu unterdrücken, die aufgrund eines nicht aktivierten Castings generiert werden, während die spätere Warnung verwendet wird, um an das Hinzufügen von SerialVersionUID in einer Serializable-Klasse zu erinnern.

Lesen Sie mehr: https://javarevisited.blogspot.com/2015/09/what-is-suppresswarnings-annotation-in-java-unchecked-raw-serial.html#ixzz5rqQaOLUa

Majid Roustaei
quelle