Java Assertion

Download Report

Transcript Java Assertion

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).
• 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.
2
Assertion …
• Assert: Detecting bugs is quicker when
assertions are included in the code.
• Assertions also document the program,
enhancing maintainability.
3
Outline
• Introduction
• Using Assertions
• Compiling Files That Use Assertions
• Enabling & Disabling Assertions
4
Introduction
• The assertion statement has 2 forms:
assert Expression; // Expression1 is boolean
Meaning:
if ( ! Expression )
{
throw AssertionError // no message
}
5
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.
6
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.
7
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 ;
8
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.
9
Outline
• Introduction
• Using Assertions
• Compiling Files That Use Assertions
• Enabling & Disabling Assertions
10
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 sideeffects.
Exception: assertions can modify state used only
from within other assertions (illustrated later).
11
Internal Invariants
Replace
With
if ( i % 3 == 0 )
if ( i % 3 == 0 )
{ ... }
{ ... }
else if ( i % 3 == 1 )
{ ... }
else
{
else if ( i % 3 == 1 )
{ ... }
else
{
assert i % 3 == 2 : i;
// We know ( i % 3 == 2 )
...
}
...
}
// assert fails for i = -5
12
Control-Flow Invariants
Use: assert false; // an unreachable point
Replace
With
void foo()
void foo()
{
{
for (...)
for (...)
{
{
if (...) return;
if (...) return;
}
}
// unreachable point
}
assert false; // unreachable
}
13
Control-Flow Invariants
Use: 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(); ”
14
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);
}
15
Preconditions …
• Assert a nonpublic method's precondition.
• An assertion is appropriate in the following
“helper” method invoked by the previous
method.
16
/**
* 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.
17
Lock-Status Precondition
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);
...
}
18
Postconditions
Replace
void push( Object o )
{
With
void push( Object o )
{
…
…
stack.add( ++top, o );
stack.add( ++top, o );
// top == stack.size();
assert top == stack.size() : “top: ”
}
+ top + “, size: ” + stack.size();
}
19
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.
20
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();
21
}
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();
22
Outline
• Introduction
• Using Assertions
• Compiling Files That Use Assertions
• Enabling & Disabling Assertions
• Compatibility with Existing Programs
23
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
24
Outline
• Introduction
• Using Assertions
• Compiling Files That Use Assertions
• Enabling & Disabling Assertions
25
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.
26
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
27
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
28