728 Stimmen

Was bewirkt das Java-Schlüsselwort assert, und wann sollte es verwendet werden?

Was sind einige Beispiele aus der Praxis die Schlüsselrolle von Behauptungen zu verstehen?

13voto

Donal Fellows Punkte 125686

Assertions werden verwendet, um Nachbedingungen und Vorbedingungen zu prüfen, die niemals fehlschlagen sollten. Korrekter Code sollte niemals an einer Assertion scheitern; wenn sie auslöst, sollte sie auf einen Fehler hinweisen (hoffentlich an einer Stelle, die nahe am tatsächlichen Ort des Problems liegt).

Ein Beispiel für eine Assertion wäre die Überprüfung, ob eine bestimmte Gruppe von Methoden in der richtigen Reihenfolge aufgerufen wird (z. B., dass hasNext() aufgerufen wird, bevor next() in einem Iterator ).

13voto

Was bewirkt das Schlüsselwort assert in Java?

Schauen wir uns den kompilierten Bytecode an.

Daraus werden wir schließen:

public class Assert {
    public static void main(String[] args) {
        assert System.currentTimeMillis() == 0L;
    }
}

erzeugt fast genau den gleichen Bytecode wie:

public class Assert {
    static final boolean $assertionsDisabled =
        !Assert.class.desiredAssertionStatus();
    public static void main(String[] args) {
        if (!$assertionsDisabled) {
            if (System.currentTimeMillis() != 0L) {
                throw new AssertionError();
            }
        }
    }
}

donde Assert.class.desiredAssertionStatus() es true cuando -ea in der Befehlszeile übergeben wird, andernfalls false.

Wir verwenden System.currentTimeMillis() um sicherzustellen, dass es nicht wegoptimiert wird ( assert true; tat).

Das synthetische Feld wird so generiert, dass Java nur noch die Assert.class.desiredAssertionStatus() einmal zum Zeitpunkt des Ladens und speichert das Ergebnis dann dort. Siehe auch: Was bedeutet der Begriff "statische Synthetik"?

Wir können das mit überprüfen:

javac Assert.java
javap -c -constants -private -verbose Assert.class

Mit Oracle JDK 1.8.0_45 wurde ein synthetisches statisches Feld erzeugt (siehe auch: Was bedeutet der Begriff "statische Synthetik"? ) :

static final boolean $assertionsDisabled;
  descriptor: Z
  flags: ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC

zusammen mit einem statischen Initialisierer:

 0: ldc           #6                  // class Assert
 2: invokevirtual #7                  // Method java/lang Class.desiredAssertionStatus:()Z
 5: ifne          12
 8: iconst_1
 9: goto          13
12: iconst_0
13: putstatic     #2                  // Field $assertionsDisabled:Z
16: return

und die Hauptmethode ist:

 0: getstatic     #2                  // Field $assertionsDisabled:Z
 3: ifne          22
 6: invokestatic  #3                  // Method java/lang/System.currentTimeMillis:()J
 9: lconst_0
10: lcmp
11: ifeq          22
14: new           #4                  // class java/lang/AssertionError
17: dup
18: invokespecial #5                  // Method java/lang/AssertionError."<init>":()V
21: athrow
22: return

Daraus schließen wir:

  • Es gibt keine Unterstützung auf Bytecode-Ebene für assert : es ist ein Konzept der Java-Sprache
  • assert konnte mit den Systemeigenschaften ziemlich gut emuliert werden -Pcom.me.assert=true zu ersetzen -ea in der Befehlszeile und ein throw new AssertionError() .

10voto

solomkinmv Punkte 1655

Mit einer Assertion lassen sich Fehler im Code aufdecken. Sie können Assertions zum Testen und Debuggen aktivieren, während Sie sie in der Produktionsphase Ihres Programms deaktiviert lassen.

Warum etwas behaupten, wenn man weiß, dass es wahr ist? Es ist nur wahr, wenn alles richtig funktioniert. Wenn das Programm einen Fehler hat, ist sie vielleicht nicht wahr. Wenn man dies früher im Prozess erkennt, weiß man, dass etwas nicht in Ordnung ist.

Eine assert Anweisung enthält diese Anweisung zusammen mit einer optionalen String Nachricht.

Die Syntax für eine Assert-Anweisung hat zwei Formen:

assert boolean_expression;
assert boolean_expression: error_message;

Hier sind einige Grundregeln, die regeln, wo Behauptungen verwendet werden sollten und wo sie nicht verwendet werden sollten. Behauptungen devrait verwendet werden:

  1. Validierung der Eingabeparameter einer privaten Methode. NICHT für öffentliche Methoden. public Methoden sollten reguläre Ausnahmen auslösen, wenn falsche Parameter übergeben werden.

  2. Irgendwo im Programm, um die Gültigkeit einer Tatsache zu gewährleisten, die mit ziemlicher Sicherheit wahr ist.

Wenn Sie zum Beispiel sicher sind, dass es nur entweder 1 oder 2 sein wird, können Sie eine Behauptung wie diese verwenden:

...
if (i == 1)    {
    ...
}
else if (i == 2)    {
    ...
} else {
    assert false : "cannot happen. i is " + i;
}
...
  1. Validierung von Nachbedingungen am Ende einer Methode. Das bedeutet, dass Sie nach der Ausführung der Geschäftslogik Assertions verwenden können, um sicherzustellen, dass der interne Zustand Ihrer Variablen oder Ergebnisse mit den Erwartungen übereinstimmt. Zum Beispiel kann eine Methode, die einen Socket oder eine Datei öffnet, am Ende eine Behauptung verwenden, um sicherzustellen, dass der Socket oder die Datei tatsächlich geöffnet ist.

Behauptungen sollte nicht verwendet werden:

  1. Validierung der Eingabeparameter einer öffentlichen Methode. Da Assertions möglicherweise nicht immer ausgeführt werden, sollte der reguläre Ausnahmemechanismus verwendet werden.

  2. Validierung von Beschränkungen für etwas, das vom Benutzer eingegeben wird. Dasselbe wie oben.

  3. Sollte nicht für Nebenwirkungen verwendet werden.

Dies ist zum Beispiel keine ordnungsgemäße Verwendung, weil hier die Behauptung für ihren Nebeneffekt des Aufrufs der doSomething() Methode.

public boolean doSomething() {
...    
}
public void someMethod() {       
assert doSomething(); 
}

Der einzige Fall, in dem dies gerechtfertigt sein könnte, ist, wenn Sie herausfinden wollen, ob Assertions in Ihrem Code aktiviert sind oder nicht:   

boolean enabled = false;    
assert enabled = true;    
if (enabled) {
    System.out.println("Assertions are enabled");
} else {
    System.out.println("Assertions are disabled");
}

8voto

Björn Punkte 28353

Ein Beispiel aus der Praxis, aus einer Stack-Klasse (aus Assertion in Java-Artikeln )

public int pop() {
   // precondition
   assert !isEmpty() : "Stack is empty";
   return stack[--num];
}

5voto

Ivan Bartsov Punkte 17774

Zusätzlich zu all den großartigen Antworten, die hier gegeben werden, enthält das offizielle Java SE 7-Programmierhandbuch ein ziemlich präzises Handbuch zur Verwendung von assert mit mehreren treffenden Beispielen, wann es eine gute (und vor allem schlechte) Idee ist, Assertions zu verwenden, und worin der Unterschied zum Auslösen von Ausnahmen besteht.

Link

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