370 likes | 688 Views
The Java Assertion. Assertion. A Java statement in JDK 1.4 & newer Intent : enables code to test assumptions. E.g., a method that calculates the a particle’s speed, asserts: speed < c (speed of light).
E N D
Assertion • A Java statement in JDK 1.4 & newer • Intent: enables code to test assumptions. E.g., a method that calculates the a particle’s speed, asserts: speed < c (speed of light). • Has a boolean expression whose value is “asserted” to be true when the assertion executes. • If it is false, the system throws an error. • By evaluating the boolean expression, the assertion confirms assumptions about program behavior. Increases confidence that the program is error-free.
Assertion … • Assert: Detecting bugs is quicker when assertions are included in the code. • Assertions also document the program, enhancing maintainability.
Outline • Introduction • Using Assertions • Compiling Files That Use Assertions • Enabling & Disabling Assertions
Introduction • The assertion statement has 2 forms: assert Expression;// Expression1 is boolean Meaning: if ( ! Expression ) { throw AssertionError// no message }
Introduction … assert Expression1 : Expression2 ; where: • Expression1 is boolean • Expression2 has a value Cannot be the returned value of a void method. Meaning: if ( ! Expression1 ) { throw new AssertionError( Expression2 ) } // Expression2’s String value is the message.
The Message • Should convey details of the assertion failure • Is not a user-level message • Need not be understandable in isolation • Is intended for use with: • a full stack trace • the source code.
Introduction … • The stack trace gives the file/line# of the failed assertion. • Use the message form only to add information that helps diagnose the failure. E.g., if Expression1 involves a relationship between variables x & y, use the message form. E.g., assert x < y : “x: “ + x + “, y: “ + y ;
Introduction … • Assertions can be enabled or disabled when the program is started. • Assertions are disabled by default. • Disabled assertions are equivalent to empty statements in semantics & performance.
Outline • Introduction • Using Assertions • Compiling Files That Use Assertions • Enabling & Disabling Assertions
Using Assertions • Do not use assertions for: argument checking in public methods. Argument checking is part of the method’s published specifications (or contract): Specifications are obeyed whether or not assertions are enabled. • Assert’s expression should have no side-effects. Exception: assertions can modify state used only from within other assertions (illustrated later).
Replace if ( i % 3 == 0 ) { ... } else if ( i % 3 == 1 ) { ... } else { // We know ( i % 3 == 2 ) ... } With if ( i % 3 == 0 ) { ... } else if ( i % 3 == 1 ) { ... } else { assert i % 3 == 2 : i; ... } // assert fails for i = -5 Internal Invariants
Replace void foo() { for (...) { if (...) return; } // unreachable point } With void foo() { for (...) { if (...) return; } assert false;// unreachable } Control-Flow InvariantsUse: assert false;// an unreachable point
Control-Flow InvariantsUse: assert false;// an unreachable point • The foregoing only makes sense if reaching a point is possible but erroneous. • If it is impossible, the compiler handles it. • If it is possible, you may always throw an exception Not just when assertions are enabled. Replace “assert false; ” with “throw new AssertionError(); ”
Preconditions • Do not assert method contracts /** * Sets the refresh rate. * @param rate refresh rate, in frames per second. * @throws IllegalArgumentException if rate <= 0 or * rate > MAX_REFRESH_RATE. */ public void setRefreshRate(int rate) { // Enforce specified precondition in public method if (rate <= 0 || rate > MAX_REFRESH_RATE) throw new IllegalArgumentException("Illegal rate: " + rate); setRefreshInterval(1000/rate); }
Preconditions … • Assert a nonpublic method's precondition. • An assertion is appropriate in the following “helper” method invoked by the previous method.
/** * Sets the refresh interval (to a legal frame rate). * @param interval refresh interval in milliseconds. */ private void setRefreshInterval( int interval ) { // Confirm adherence to precondition in nonpublic method assert interval > 0 && interval <= 1000/MAX_REFRESH_RATE : interval; ... // Set the refresh interval } The assertion can fail if MAX_REFRESH_RATE > 1000.
Original private Object[] a; public synchronized int find(Object key) { return find(key, a, 0, a.length); } // Recursive helper method: always has lock on this private int find(Object key, Object[] arr, int start, int len) { ... } Assert lock status: // Recursive helper method: always has lock on this. private int find(Object key, Object[] arr, int start, int len) { // lock-status assertion assert Thread.holdsLock(this); ... } Lock-Status Precondition
Replace void push( Object o ) { … stack.add( ++top, o ); // top == stack.size(); } With void push( Object o ) { … stack.add( ++top, o ); assert top == stack.size() : “top: ” + top + “, size: ” + stack.size(); } Postconditions
Postconditions … • An assert’s expression may need state. void foo(int[] array) { // Manipulate array ... // At this point, array contents == itself // prior to manipulation } Replace the above with the following.
Postconditions … void foo(final int[] array) { // Inner class that saves state & performs final consistency check class DataCopy { private int[] arrayCopy; DataCopy() { arrayCopy = ( int[] ) array.clone(); } boolean isConsistent() { return Arrays.equals( array, arrayCopy ); } } DataCopy copy = null; // Always succeeds; has side effect of saving a copy of array assert ( ( copy = new DataCopy() ) != null ); // copy only if ea ... // Manipulate array // Ensure array has same ints in same order as before. assert copy.isConsistent(); }
Class State Invariants • Class state invariant: an invariant that applies to all instances at the beginning & ending of all methods. E.g., in a balanced tree, a class invariant is that the tree is balanced. • Style: combine the expressions that check required constraints into an internal method. // Returns true if this tree is properly balanced private boolean isBalanced() { ... } • Assert class invariant just prior to return from public methods & constructors: assert isBalanced();
Outline • Introduction • Using Assertions • Compiling Files That Use Assertions • Enabling & Disabling Assertions • Compatibility with Existing Programs
Compiling Files That Use Assertions To tell javac to accept assertions, use the -source 1.4 command-line option: javac -source 1.4 MyClass.java
Outline • Introduction • Using Assertions • Compiling Files That Use Assertions • Enabling & Disabling Assertions
Enabling & Disabling Assertions • By default, assertions are disabled. • Enable assertions, using the -ea, switch. • Disable assertions, using the -da, switch. • Specify granularity as the switch argument: • no arguments Enables/disables assertions in all classes except system classes. • packageName... Enables/disables assertions in the package & any subpackages. • ... Enables/disables assertions in the unnamed package in the current working directory. • className Enables/disables assertions in the named class.
Enabling & Disabling Assertions • To run BatTutor, with assertions enabled in only package com.wombat.fruitbat & its subpackages: java -ea:com.wombat.fruitbat... BatTutor • To run BatTutor with assertions: • enabled in package com.wombat.fruitbat • disabled in class com.wombat.fruitbat.Brickbat: java -ea:com.wombat.fruitbat... -da:com.wombat.fruitbat.Brickbat BatTutor
Enabling & Disabling Assertions To (en/dis)able system class assertions, use: -esa -dsa To run BatTutor with assertions: • enabled in system classes, • enabled in the com.wombat.fruitbat package & its subpackages: java -esa-ea:com.wombat.fruitbat... BatTutor