Was sind einige Beispiele aus dem wirklichen Leben , um die Schlüsselrolle von Behauptungen zu verstehen?
Was sind einige Beispiele aus dem wirklichen Leben , um die Schlüsselrolle von Behauptungen zu verstehen?
Antworten:
Assertions (über das Schlüsselwort assert ) wurden in Java 1.4 hinzugefügt. Sie werden verwendet, um die Richtigkeit einer Invariante im Code zu überprüfen. Sie sollten niemals im Produktionscode ausgelöst werden und weisen auf einen Fehler oder Missbrauch eines Codepfads hin. Sie können zur Laufzeit über die -ea
Option im java
Befehl aktiviert werden , sind jedoch standardmäßig nicht aktiviert.
Ein Beispiel:
public Foo acquireFoo(int id) {
Foo result = null;
if (id > 50) {
result = fooService.read(id);
} else {
result = new Foo(id);
}
assert result != null;
return result;
}
assert
, die Parameter öffentlicher Methoden nicht zu überprüfen ( docs.oracle.com/javase/1.4.2/docs/guide/lang/assert.html ). Das sollte ein werfen, Exception
anstatt das Programm zu töten.
This convention is unaffected by the addition of the assert construct. Do not use assertions to check the parameters of a public method. An assert is inappropriate because the method guarantees that it will always enforce the argument checks. It must check its arguments whether or not assertions are enabled. Further, the assert construct does not throw an exception of the specified type. It can throw only an AssertionError.
docs.oracle.com/javase/8/docs/technotes/guides/language/…
Nehmen wir an, Sie sollen ein Programm zur Steuerung eines Kernkraftwerks schreiben. Es ist ziemlich offensichtlich, dass selbst der kleinste Fehler katastrophale Folgen haben kann, daher muss Ihr Code sein fehlerfrei (unter der Annahme , dass die JVM ist fehlerfrei im Interesse des Arguments).
Java ist keine überprüfbare Sprache, was bedeutet: Sie können nicht berechnen, dass das Ergebnis Ihrer Operation perfekt ist. Der Hauptgrund dafür sind Zeiger: Sie können überall oder nirgendwo zeigen, daher können sie nicht so berechnet werden, dass sie genau diesen Wert haben, zumindest nicht innerhalb eines angemessenen Codebereichs. Angesichts dieses Problems gibt es keine Möglichkeit zu beweisen, dass Ihr Code insgesamt korrekt ist. Sie können jedoch beweisen, dass Sie zumindest jeden Fehler finden, wenn er auftritt.
Diese Idee basiert auf dem DbC-Paradigma ( Design-by-Contract ): Sie definieren zunächst (mit mathematischer Genauigkeit), was Ihre Methode tun soll, und überprüfen dies dann, indem Sie sie während der tatsächlichen Ausführung testen. Beispiel:
// Calculates the sum of a (int) + b (int) and returns the result (int).
int sum(int a, int b) {
return a + b;
}
Obwohl dies ziemlich offensichtlich gut funktioniert, werden die meisten Programmierer den versteckten Fehler in diesem nicht sehen (Hinweis: Die Ariane V ist aufgrund eines ähnlichen Fehlers abgestürzt). Jetzt definiert DbC, dass Sie immer die Ein- und Ausgabe einer Funktion überprüfen müssen, um sicherzustellen, dass sie ordnungsgemäß funktioniert. Java kann dies durch Behauptungen tun:
// Calculates the sum of a (int) + b (int) and returns the result (int).
int sum(int a, int b) {
assert (Integer.MAX_VALUE - a >= b) : "Value of " + a + " + " + b + " is too large to add.";
final int result = a + b;
assert (result - a == b) : "Sum of " + a + " + " + b + " returned wrong sum " + result;
return result;
}
Sollte diese Funktion jetzt jemals fehlschlagen, werden Sie es bemerken. Sie werden wissen, dass es ein Problem in Ihrem Code gibt, Sie wissen, wo es ist und was es verursacht hat (ähnlich wie bei Ausnahmen). Und was noch wichtiger ist: Sie beenden die Ausführung richtig, wenn verhindert wird, dass weiterer Code mit falschen Werten arbeitet, und möglicherweise das, was er steuert, beschädigt.
Java-Ausnahmen sind ein ähnliches Konzept, aber sie können nicht alles überprüfen. Wenn Sie noch mehr Überprüfungen wünschen (auf Kosten der Ausführungsgeschwindigkeit), müssen Sie Zusicherungen verwenden. Wenn Sie dies tun, wird Ihr Code aufgebläht, aber Sie können am Ende ein Produkt in einer überraschend kurzen Entwicklungszeit liefern (je früher Sie einen Fehler beheben, desto geringer sind die Kosten). Und außerdem: Wenn Ihr Code einen Fehler enthält, werden Sie ihn erkennen. Es gibt keine Möglichkeit, dass ein Fehler auftritt und später Probleme verursacht.
Dies ist immer noch keine Garantie für fehlerfreien Code, aber es ist viel näher daran als übliche Programme.
new IllegalArgumentException
mit der Nachricht zu werfen ? Ich meine, abgesehen davon, dass o throws
der Methodendeklaration und dem Code hinzugefügt werden muss, um diese Ausnahme woanders zu verwalten. Warum assert
sollte man eine neue Ausnahme auslösen? Oder warum nicht ein if
statt assert
? Kann das nicht wirklich
a
sie negativ sein kann. Die zweite Behauptung ist nutzlos; Für int-Werte ist es immer so, dass a + b - b == a. Dieser Test kann nur fehlschlagen, wenn der Computer grundlegend defekt ist. Um sich gegen diese Eventualität zu verteidigen, müssen Sie die Konsistenz über mehrere CPUs hinweg überprüfen.
Assertions sind ein Tool in der Entwicklungsphase, um Fehler in Ihrem Code zu erkennen. Sie sind so konzipiert, dass sie leicht entfernt werden können, sodass sie im Produktionscode nicht vorhanden sind. Behauptungen sind also nicht Teil der "Lösung", die Sie dem Kunden liefern. Es handelt sich um interne Überprüfungen, um sicherzustellen, dass die von Ihnen getroffenen Annahmen korrekt sind. Das häufigste Beispiel ist das Testen auf Null. Viele Methoden sind so geschrieben:
void doSomething(Widget widget) {
if (widget != null) {
widget.someMethod(); // ...
... // do more stuff with this widget
}
}
Sehr oft sollte bei einer solchen Methode das Widget einfach niemals null sein. Wenn es also null ist, gibt es irgendwo einen Fehler in Ihrem Code, den Sie aufspüren müssen. Aber der obige Code wird Ihnen dies niemals sagen. In einem gut gemeinten Versuch, "sicheren" Code zu schreiben, verstecken Sie auch einen Fehler. Es ist viel besser, Code wie folgt zu schreiben:
/**
* @param Widget widget Should never be null
*/
void doSomething(Widget widget) {
assert widget != null;
widget.someMethod(); // ...
... // do more stuff with this widget
}
Auf diese Weise können Sie diesen Fehler sicher frühzeitig erkennen. (Es ist auch nützlich, im Vertrag anzugeben, dass dieser Parameter niemals null sein darf.) Aktivieren Sie unbedingt die Zusicherungen, wenn Sie Ihren Code während der Entwicklung testen. (Und es ist oft schwierig, Ihre Kollegen dazu zu überreden, was ich sehr ärgerlich finde.)
Nun werden einige Ihrer Kollegen Einwände gegen diesen Code erheben und argumentieren, dass Sie immer noch die Nullprüfung durchführen sollten, um eine Ausnahme in der Produktion zu verhindern. In diesem Fall ist die Behauptung immer noch nützlich. Sie können es so schreiben:
void doSomething(Widget widget) {
assert widget != null;
if (widget != null) {
widget.someMethod(); // ...
... // do more stuff with this widget
}
}
Auf diese Weise werden Ihre Kollegen froh sein, dass die Nullprüfung für Produktionscode vorhanden ist, aber während der Entwicklung verbergen Sie den Fehler nicht mehr, wenn das Widget null ist.
Hier ist ein Beispiel aus der Praxis: Ich habe einmal eine Methode geschrieben, die zwei beliebige Werte auf Gleichheit vergleicht, wobei jeder Wert null sein kann:
/**
* Compare two values using equals(), after checking for null.
* @param thisValue (may be null)
* @param otherValue (may be null)
* @return True if they are both null or if equals() returns true
*/
public static boolean compare(final Object thisValue, final Object otherValue) {
boolean result;
if (thisValue == null) {
result = otherValue == null;
} else {
result = thisValue.equals(otherValue);
}
return result;
}
Dieser Code delegiert die Arbeit der equals()
Methode für den Fall, dass thisValue nicht null ist. Es wird jedoch davon ausgegangen, dass die equals()
Methode den Vertrag von korrekt erfülltequals()
indem ein Nullparameter ordnungsgemäß behandelt wird.
Ein Kollege widersprach meinem Code und sagte mir, dass viele unserer Klassen fehlerhafte equals()
Methoden haben, die nicht auf Null getestet werden. Deshalb sollte ich diese Prüfung in diese Methode einfügen . Es ist fraglich, ob dies sinnvoll ist oder ob wir den Fehler erzwingen sollten, damit wir ihn erkennen und beheben können, aber ich habe mich an meinen Kollegen gewandt und einen Null-Check durchgeführt, den ich mit einem Kommentar markiert habe:
public static boolean compare(final Object thisValue, final Object otherValue) {
boolean result;
if (thisValue == null) {
result = otherValue == null;
} else {
result = otherValue != null && thisValue.equals(otherValue); // questionable null check
}
return result;
}
Die zusätzliche Prüfung hier other != null
ist nur erforderlich, wenn dieequals()
Methode nicht wie im Vertrag vorgeschrieben auf Null prüft.
Anstatt mit meinem Kollegen eine fruchtlose Debatte über die Weisheit zu führen, den fehlerhaften Code in unserer Codebasis zu belassen, habe ich einfach zwei Aussagen in den Code eingefügt. Diese Behauptungen lassen mich während der Entwicklungsphase wissen, wenn eine unserer Klassen nicht equals()
ordnungsgemäß implementiert wird, sodass ich das Problem beheben kann:
public static boolean compare(final Object thisValue, final Object otherValue) {
boolean result;
if (thisValue == null) {
result = otherValue == null;
assert otherValue == null || otherValue.equals(null) == false;
} else {
result = otherValue != null && thisValue.equals(otherValue);
assert thisValue.equals(null) == false;
}
return result;
}
Die wichtigsten Punkte, die zu beachten sind, sind folgende:
Behauptungen sind nur Werkzeuge in der Entwicklungsphase.
Der Sinn einer Behauptung besteht darin, Sie wissen zu lassen, ob ein Fehler vorliegt, nicht nur in Ihrem Code, sondern auch in Ihrer Codebasis . (Die Behauptungen hier kennzeichnen tatsächlich Fehler in anderen Klassen.)
Selbst wenn mein Kollege zuversichtlich wäre, dass unsere Klassen richtig geschrieben wurden, wären die Aussagen hier immer noch nützlich. Es werden neue Klassen hinzugefügt, die möglicherweise nicht auf Null getestet werden können, und diese Methode kann diese Fehler für uns kennzeichnen.
In der Entwicklung sollten Sie Assertions immer aktivieren, auch wenn der von Ihnen geschriebene Code keine Assertions verwendet. Meine IDE ist so eingestellt, dass dies bei jeder neuen ausführbaren Datei standardmäßig immer der Fall ist.
Die Behauptungen ändern nichts am Verhalten des Codes in der Produktion, daher ist mein Kollege froh, dass die Nullprüfung vorhanden ist und dass diese Methode auch dann ordnungsgemäß ausgeführt wird, wenn die equals()
Methode fehlerhaft ist. Ich bin glücklich, weil ich jede fehlerhafte equals()
Methode in der Entwicklung fangen werde .
Außerdem sollten Sie Ihre Assertionsrichtlinie testen, indem Sie eine temporäre Assertion eingeben, die fehlschlägt, damit Sie sicher sein können, dass Sie entweder über die Protokolldatei oder eine Stapelverfolgung im Ausgabestream benachrichtigt werden.
Viele gute Antworten, die erklären, was das assert
Schlüsselwort bewirkt, aber nur wenige, die die eigentliche Frage beantworten: "Wann sollte das?assert
Schlüsselwort im wirklichen Leben verwendet werden?"
Die Antwort: fast nie .
Behauptungen als Konzept sind wunderbar. Guter Code hat viele if (...) throw ...
Aussagen (und ihre Verwandten mögen Objects.requireNonNull
und Math.addExact
). Bestimmte Entwurfsentscheidungen haben jedoch die Nützlichkeit des assert
Schlüsselworts selbst stark eingeschränkt .
Die treibende Idee hinter dem assert
Schlüsselwort ist die vorzeitige Optimierung, und das Hauptmerkmal besteht darin, dass alle Überprüfungen einfach deaktiviert werden können. Tatsächlich sind die assert
Überprüfungen standardmäßig deaktiviert.
Es ist jedoch von entscheidender Bedeutung, dass in der Produktion weiterhin invariante Überprüfungen durchgeführt werden. Dies liegt daran, dass eine perfekte Testabdeckung nicht möglich ist und der gesamte Produktionscode Fehler enthält, deren Behauptungen zur Diagnose und Minderung beitragen sollten.
Daher sollte die Verwendung von if (...) throw ...
bevorzugt werden, genau wie es zum Überprüfen von Parameterwerten öffentlicher Methoden und zum Werfen erforderlich ist IllegalArgumentException
.
Gelegentlich könnte man versucht sein, einen invarianten Scheck zu schreiben, dessen Verarbeitung unerwünscht lange dauert (und der oft genug aufgerufen wird, damit er eine Rolle spielt). Solche Überprüfungen verlangsamen jedoch das Testen, was ebenfalls unerwünscht ist. Solche zeitaufwändigen Prüfungen werden normalerweise als Komponententests geschrieben. Trotzdem kann es manchmal sinnvoll sein, es zu verwendenassert
aus diesem Grund zu verwenden.
Verwenden Sie es nicht assert
einfach, weil es sauberer und hübscher ist als if (...) throw ...
(und das sage ich mit großen Schmerzen, weil ich es sauber und hübsch mag). Wenn Sie sich einfach nicht selbst helfen können und steuern können, wie Ihre Anwendung gestartet wird, können Sie sie verwenden, assert
aber immer Aussagen in der Produktion aktivieren. Zugegeben, das ist es, was ich tendenziell mache. Ich dränge auf eine lombok Anmerkung , die bewirkt , dass assert
mehr wie handeln if (...) throw ...
.Stimmen Sie hier dafür ab.
(Rant: Die JVM-Entwickler waren eine Menge schrecklicher, vorzeitig optimierter Codierer. Deshalb hören Sie von so vielen Sicherheitsproblemen im Java-Plugin und in der JVM. Sie haben sich geweigert, grundlegende Überprüfungen und Zusicherungen in den Produktionscode aufzunehmen, und wir fahren fort Zahl den Preis.)
catch (Throwable t)
. Es gibt keinen Grund, nicht zu versuchen, OutOfMemoryError, AssertionError usw. abzufangen, zu protokollieren oder erneut zu versuchen / wiederherzustellen.
assert
Schlüsselworts schlecht. Ich werde meine Antwort bearbeiten, um klarer zu machen, dass ich mich auf das Schlüsselwort und nicht auf das Konzept beziehe.
Hier ist der häufigste Anwendungsfall. Angenommen, Sie schalten einen Aufzählungswert ein:
switch (fruit) {
case apple:
// do something
break;
case pear:
// do something
break;
case banana:
// do something
break;
}
Solange Sie jeden Fall bearbeiten, geht es Ihnen gut. Aber eines Tages wird jemand Feigen zu Ihrer Aufzählung hinzufügen und vergessen, sie Ihrer switch-Anweisung hinzuzufügen. Dies führt zu einem Fehler, der möglicherweise schwierig zu erkennen ist, da die Auswirkungen erst nach dem Verlassen der switch-Anweisung zu spüren sind. Aber wenn Sie Ihren Schalter so schreiben, können Sie ihn sofort fangen:
switch (fruit) {
case apple:
// do something
break;
case pear:
// do something
break;
case banana:
// do something
break;
default:
assert false : "Missing enum value: " + fruit;
}
AssertionError
wenn Zusicherungen aktiviert sind ( -ea
). Was ist das gewünschte Verhalten in der Produktion? Ein stilles No-Op und eine mögliche Katastrophe später in der Hinrichtung? Wahrscheinlich nicht. Ich würde eine explizite vorschlagen throw new AssertionError("Missing enum value: " + fruit);
.
default
damit der Compiler Sie bei fehlenden Fällen warnen kann. Sie können return
stattdessen break
(dies muss möglicherweise die Methode extrahieren) den fehlenden Fall nach dem Wechsel behandeln. Auf diese Weise erhalten Sie sowohl die Warnung als auch die Gelegenheit dazu assert
.
Assertions werden verwendet, um die Nachbedingungen zu überprüfen und die Vorbedingungen "sollte niemals scheitern". Richtiger Code sollte niemals eine Behauptung verfehlen. Wenn sie ausgelöst werden, sollten sie auf einen Fehler hinweisen (hoffentlich an einem Ort, der sich in der Nähe des tatsächlichen Ortes des Problems befindet).
Ein Beispiel für eine Behauptung könnte darin bestehen, zu überprüfen, ob eine bestimmte Gruppe von Methoden in der richtigen Reihenfolge aufgerufen wird (z. B. die hasNext()
zuvor next()
in einer aufgerufen wurde Iterator
).
Was macht das Schlüsselwort assert in Java?
Schauen wir uns den kompilierten Bytecode an.
Wir werden daraus schließen, dass:
public class Assert {
public static void main(String[] args) {
assert System.currentTimeMillis() == 0L;
}
}
generiert 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();
}
}
}
}
wo Assert.class.desiredAssertionStatus()
ist true
wann-ea
wird in der Befehlszeile übergeben, andernfalls falsch.
Wir verwenden, System.currentTimeMillis()
um sicherzustellen, dass es nicht weg optimiert wird ( assert true;
tat).
Das synthetische Feld wird so generiert, dass Java Assert.class.desiredAssertionStatus()
beim Laden nur einmal aufrufen muss , und speichert dann das Ergebnis dort zwischen. Siehe auch: Was bedeutet "statisch synthetisch"?
Wir können dies überprüfen mit:
javac Assert.java
javap -c -constants -private -verbose Assert.class
Mit Oracle JDK 1.8.0_45 wurde ein synthetisches statisches Feld generiert (siehe auch: Was bedeutet "statisches synthetisches"? ):
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
Wir schließen daraus:
assert
: Es handelt sich um ein Java-Sprachkonzeptassert
könnte ziemlich gut mit Systemeigenschaften emuliert werden -Pcom.me.assert=true
, die -ea
in der Befehlszeile ersetzt werden sollen, und a throw new AssertionError()
.catch (Throwable t)
Klausel kann also auch Verstöße gegen die Behauptung auffangen? Für mich beschränkt sich ihre Nützlichkeit nur auf den Fall, dass der Körper der Behauptung zeitaufwändig ist, was selten vorkommt.
AssertionError
erste fangen und es erneut werfen.
Ein Beispiel aus der realen Welt aus einer Stack-Klasse (aus Assertion in Java Articles )
public int pop() {
// precondition
assert !isEmpty() : "Stack is empty";
return stack[--num];
}
Eine Zusicherung ermöglicht das Erkennen von Fehlern im Code. Sie können Zusicherungen zum Testen und Debuggen aktivieren, während Sie sie deaktivieren, wenn Ihr Programm in Produktion ist.
Warum etwas behaupten, wenn Sie wissen, dass es wahr ist? Es ist nur wahr, wenn alles richtig funktioniert. Wenn das Programm einen Fehler aufweist, ist dies möglicherweise nicht der Fall. Wenn Sie dies früher im Prozess erkennen, wissen Sie, dass etwas nicht stimmt.
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 sollen und wo sie nicht verwendet werden sollen. Behauptungen sollten verwendet werden für:
Validierung der Eingabeparameter einer privaten Methode. NICHT für öffentliche Methoden. public
Methoden sollten regelmäßige Ausnahmen auslösen, wenn fehlerhafte Parameter übergeben werden.
Überall im Programm, um die Gültigkeit einer Tatsache sicherzustellen, die mit ziemlicher Sicherheit wahr ist.
Wenn Sie beispielsweise sicher sind, dass es sich nur um 1 oder 2 handelt, können Sie eine Behauptung wie die folgende verwenden:
...
if (i == 1) {
...
}
else if (i == 2) {
...
} else {
assert false : "cannot happen. i is " + i;
}
...
Behauptungen sollten nicht verwendet werden für:
Validierung der Eingabeparameter einer öffentlichen Methode. Da Zusicherungen möglicherweise nicht immer ausgeführt werden, sollte der reguläre Ausnahmemechanismus verwendet werden.
Überprüfen von Einschränkungen für etwas, das vom Benutzer eingegeben wird. Das gleiche wie oben.
Sollte nicht für Nebenwirkungen verwendet werden.
Dies ist beispielsweise keine ordnungsgemäße Verwendung, da hier die Behauptung für den Nebeneffekt des Aufrufs der doSomething()
Methode verwendet wird.
public boolean doSomething() {
...
}
public void someMethod() {
assert doSomething();
}
Der einzige Fall, in dem dies gerechtfertigt sein könnte, ist, wenn Sie herausfinden möchten, ob Zusicherungen 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");
}
Zusätzlich zu all den tollen Antworten, die hier gegeben werden, enthält der offizielle Java SE 7-Programmierleitfaden ein ziemlich kurzes Handbuch zur Verwendung assert
. mit mehreren Beispielen, wann es eine gute (und vor allem schlechte) Idee ist, Behauptungen zu verwenden, und wie es sich vom Auslösen von Ausnahmen unterscheidet.
Assert ist sehr nützlich bei der Entwicklung. Sie verwenden es, wenn etwas einfach nicht kann passieren , wenn Ihr Code ordnungsgemäß funktioniert. Es ist einfach zu bedienen und kann für immer im Code bleiben, da es im wirklichen Leben ausgeschaltet wird.
Wenn es eine Chance gibt, dass der Zustand im wirklichen Leben auftreten kann, müssen Sie damit umgehen.
Ich liebe es, weiß aber nicht, wie ich es in Eclipse / Android / ADT einschalten soll. Es scheint auch beim Debuggen ausgeschaltet zu sein. (Es gibt einen Thread dazu, der sich jedoch auf die 'Java VM' bezieht, die in der ADT-Ausführungskonfiguration nicht angezeigt wird.)
Hier ist eine Behauptung, die ich auf einem Server für ein Hibernate / SQL-Projekt geschrieben habe. Eine Entity-Bean hatte zwei effektiv boolesche Eigenschaften, isActive und isDefault. Jeder könnte einen Wert von "Y" oder "N" oder null haben, der als "N" behandelt wurde. Wir möchten sicherstellen, dass der Browser-Client auf diese drei Werte beschränkt ist. In meinen Setzern für diese beiden Eigenschaften habe ich diese Behauptung hinzugefügt:
assert new HashSet<String>(Arrays.asList("Y", "N", null)).contains(value) : value;
Beachten Sie Folgendes.
Diese Behauptung gilt nur für die Entwicklungsphase. Wenn der Kunde einen schlechten Wert sendet, werden wir diesen frühzeitig erkennen und beheben, lange bevor wir die Produktion erreichen. Behauptungen beziehen sich auf Mängel, die Sie frühzeitig erkennen können.
Diese Behauptung ist langsam und ineffizient. Das ist okay. Behauptungen sind frei, langsam zu sein. Es ist uns egal, weil es sich nur um Entwicklungswerkzeuge handelt. Dies wird den Produktionscode nicht verlangsamen, da Zusicherungen deaktiviert werden. (In diesem Punkt gibt es einige Meinungsverschiedenheiten, auf die ich später noch eingehen werde.) Dies führt zu meinem nächsten Punkt.
Diese Behauptung hat keine Nebenwirkungen. Ich hätte meinen Wert gegen ein nicht modifizierbares statisches endgültiges Set testen können, aber dieses Set wäre in der Produktion geblieben, wo es niemals verwendet würde.
Diese Behauptung dient dazu, den ordnungsgemäßen Betrieb des Clients zu überprüfen. Wenn wir also die Produktion erreichen, werden wir sicher sein, dass der Client ordnungsgemäß funktioniert, sodass wir die Behauptung sicher deaktivieren können.
Einige Leute fragen dies: Wenn die Behauptung in der Produktion nicht benötigt wird, warum nehmen Sie sie nicht einfach heraus, wenn Sie fertig sind? Weil Sie sie immer noch benötigen, wenn Sie mit der Arbeit an der nächsten Version beginnen.
Einige Leute haben argumentiert, dass Sie niemals Behauptungen verwenden sollten, weil Sie niemals sicher sein können, dass alle Fehler verschwunden sind, sodass Sie sie auch in der Produktion beibehalten müssen. Es macht also keinen Sinn, die assert-Anweisung zu verwenden, da der einzige Vorteil von asserts darin besteht, dass Sie sie deaktivieren können. Daher sollten Sie nach dieser Überlegung (fast) niemals Asserts verwenden. Ich stimme dir nicht zu. Es ist sicher richtig, dass Sie keinen Assert verwenden sollten, wenn ein Test in die Produktion gehört. Dieser Test tut dies jedoch nicht in die Produktion. Dieser dient dazu, einen Fehler zu erkennen, der wahrscheinlich nie die Produktion erreichen wird. Daher kann er sicher ausgeschaltet werden, wenn Sie fertig sind.
Übrigens hätte ich es so schreiben können:
assert value == null || value.equals("Y") || value.equals("N") : value;
Dies ist nur für drei Werte in Ordnung, aber wenn die Anzahl der möglichen Werte größer wird, wird die HashSet-Version bequemer. Ich habe mich für die HashSet-Version entschieden, um auf Effizienz hinzuweisen.
HashSet
einen Geschwindigkeitsvorteil gegenüber einem bringt ArrayList
. Darüber hinaus dominieren die Set- und Listenkreationen die Suchzeit. Sie würden gut damit umgehen, wenn sie eine Konstante verwenden. Das alles sagte, +1.
Assertion wird im Wesentlichen zum Debuggen der Anwendung verwendet oder als Ersatz für die Ausnahmebehandlung für einige Anwendungen, um die Gültigkeit einer Anwendung zu überprüfen.
Assertion funktioniert zur Laufzeit. Ein einfaches Beispiel, das das gesamte Konzept sehr einfach erklären kann, ist hier - Was macht das Schlüsselwort assert in Java? (WikiAnswers).
Zusicherungen sind standardmäßig deaktiviert. Um sie zu aktivieren, müssen wir das Programm mit -ea
Optionen ausführen (Granularität kann variiert werden). Zum Beispiel java -ea AssertionsDemo
.
Es gibt zwei Formate für die Verwendung von Zusicherungen:
assert 1==2; // This will raise an AssertionError
.assert 1==2: "no way.. 1 is not equal to 2";
Dies löst einen AssertionError mit der angezeigten Meldung aus und ist daher besser. Obwohl in der eigentlichen Syntax assert expr1:expr2
expr2 ein beliebiger Ausdruck sein kann, der einen Wert zurückgibt, habe ich ihn häufiger nur zum Drucken einer Nachricht verwendet.Um es noch einmal zusammenzufassen (und dies gilt für viele Sprachen, nicht nur für Java):
"assert" wird hauptsächlich als Debugging-Hilfe von Softwareentwicklern während des Debugging-Prozesses verwendet. Assert-Nachrichten sollten niemals erscheinen. Viele Sprachen bieten eine Option zur Kompilierungszeit, die dazu führt, dass alle "Asserts" ignoriert werden, um "Produktions" -Code zu generieren.
"Ausnahmen" sind eine praktische Möglichkeit, alle Arten von Fehlerzuständen zu behandeln, unabhängig davon, ob sie logische Fehler darstellen oder nicht. Wenn Sie auf einen Fehlerzustand stoßen, bei dem Sie nicht fortfahren können, können Sie sie einfach "in die Luft werfen". "Von wo auch immer Sie sind, erwarten Sie, dass jemand anderes bereit ist, sie zu" fangen ". Die Kontrolle wird in einem Schritt direkt vom Code, der die Ausnahme ausgelöst hat, direkt auf den Handschuh des Fängers übertragen. (Und der Fänger kann die vollständige Rückverfolgung der getätigten Anrufe sehen.)
Darüber hinaus müssen Aufrufer dieser Unterroutine nicht überprüfen, ob die Unterroutine erfolgreich war: "Wenn wir jetzt hier sind, muss sie erfolgreich gewesen sein, da sie sonst eine Ausnahme ausgelöst hätte und wir jetzt nicht hier wären!"Diese einfache Strategie erleichtert das Code-Design und das Debuggen erheblich.
Ausnahmen ermöglichen es, dass schwerwiegende Fehlerbedingungen so sind, wie sie sind: "Ausnahmen von der Regel". Und damit sie von einem Codepfad gehandhabt werden, der auch "eine Ausnahme von der Regel ... " ist!
Behauptungen sind Prüfungen, die möglicherweise ausgeschaltet werden. Sie werden selten benutzt. Warum?
result != null
da solche Überprüfungen sehr schnell sind und kaum etwas zu speichern ist.Also, was ist noch übrig? Teure Überprüfungen auf Bedingungen, von denen wirklich erwartet wird , dass sie wahr sind. Ein gutes Beispiel wären die Invarianten einer Datenstruktur wie RB-Tree. Tatsächlich gibt es in ConcurrentHashMap
JDK8 einige derart aussagekräftige Aussagen für die TreeNodes
.
Manchmal ist der Scheck nicht wirklich teuer, aber gleichzeitig sind Sie sich ziemlich sicher, dass er bestanden wird. In meinem Code gibt es z.
assert Sets.newHashSet(userIds).size() == userIds.size();
Ich bin mir ziemlich sicher, dass die Liste, die ich gerade erstellt habe, eindeutige Elemente enthält, aber ich wollte sie dokumentieren und überprüfen.
Grundsätzlich wird "assert true" bestanden und "assert false" wird fehlschlagen. Schauen wir uns an, wie das funktionieren wird:
public static void main(String[] args)
{
String s1 = "Hello";
assert checkInteger(s1);
}
private static boolean checkInteger(String s)
{
try {
Integer.parseInt(s);
return true;
}
catch(Exception e)
{
return false;
}
}
assert
ist ein Schlüsselwort. Es wurde in JDK 1.4 eingeführt. Das sind zwei Arten von assert
s
assert
Aussagenassert
Aussagen.Standardmäßig assert
werden nicht alle Anweisungen ausgeführt. Wenn eine assert
Anweisung false erhält, wird automatisch ein Assertionsfehler ausgelöst.