6.2 | Verwendung von Zusicherungen |
Damit in einem Programm Zusicherungen geprüft werden, sind drei Schritte erforderlich:Die zusätzlich erforderliche Aktivierung von Zusicherungsprüfungen zur Laufzeit hat den Vorteil, dass sie ohne Neuübersetzung zentral ein- und ausgeschaltet werden können. So können Zusicherungen auch zur Ad-hoc-Fehlersuche schnell wieder eingeschaltet werden.
- Der Quelltext muss an den gewünschten Stellen mit assert-Anweisungen versehen werden.
- Der Quelltext muss mit Unterstützung für Zusicherungen übersetzt werden. Bei javac muss hierzu der Schalter -source 1.4 angegeben werden.
Ohne diesen Schalter behandelt javac assert nicht als Schlüsselwort, sondern als Bezeichner und liefert daher bei assert-Anweisungen entsprechende Fehlermeldungen.
- Schließlich muss die Prüfung von Zusicherungen in der Laufzeitumgebung aktiviert werden. Dies kann entweder global für das gesamte Programm oder aber nur für einzelne Pakete und Klassen erfolgen.
Wenn Klassen mit Unterstützung für Zusicherungen übersetzt wurden, enthält der Bytecode zwar die Instruktionen für die Zusicherungen, ausgeführt werden diese aber nur nach der Aktivierung. Auf diese Weise entsteht kein Performance-Verlust, wenn die Zusicherungen im Laufe des Entwicklungsprozesses nicht mehr benötigt werden.
In Fällen, in denen auch der Bytecode aus der Klasse entfernt werden soll, kann man sich folgender Technik bedienen, die gewissermaßen eine bedingte Kompilierung in Java realisiert:
- Man definiert eine boolean-Konstante, die entscheidet, ob Zusicherungen eingebaut werden sollen oder nicht.
- Man fügt vor jeder assert-Anweisung eine if-Anweisung ein, die dieses Flag abfragt. Insgesamt sieht dieses Muster folgendermaßen aus, wenn es auf das obige Beispiel angewendet wird:
final static boolean DEBUG = true; public static char[] subArray(char[] array, int start, int end) { if (array == null) throw new IllegalArgumentException(); if (start < 0) throw new IllegalArgumentException(); if (end > array.length) throw new IllegalArgumentException(); if (start > end) throw new IllegalArgumentException(); char[] result = new char[end-start]; for(int i = start; i < 10; i++) { if (DEBUG) assert (i >= 0) && (i < result.length) : "i out of bounds: "+i; result[i] = array[i]; } if (DEBUG) { assert (result != null); assert (result.length == (end-start)); } return result; }Ein guter Compiler erkennt, dass die assert-Anweisung nie erreicht wird, wenn die Konstante DEBUG auf false gesetzt ist, und entfernt die entsprechende if-Anweisung komplett aus dem Bytecode.