Was sind einige Beispiele aus der Praxis die Schlüsselrolle von Behauptungen zu verstehen?
Antworten
Zu viele Anzeigen?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
).
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 einthrow new AssertionError()
.
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:
-
Validierung der Eingabeparameter einer privaten Methode. NICHT für öffentliche Methoden.
public
Methoden sollten reguläre Ausnahmen auslösen, wenn falsche Parameter übergeben werden. -
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;
}
...
- 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:
-
Validierung der Eingabeparameter einer öffentlichen Methode. Da Assertions möglicherweise nicht immer ausgeführt werden, sollte der reguläre Ausnahmemechanismus verwendet werden.
-
Validierung von Beschränkungen für etwas, das vom Benutzer eingegeben wird. Dasselbe wie oben.
-
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");
}
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];
}
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.