|
|
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 2 of 9
Exception in thread "main" java.lang.AssertionError
at AssertDemo.main(AssertDemo.java:6)
This message is somewhat cryptic in that it doesn't identify what caused the AssertionError to be thrown. If you want a more informative message, use the assert statement expressed below:
assert BooleanExpr : expr;
Here, expr is any expression (including a method invocation) that can return a value -- you cannot invoke a method with a void return type. A useful expression is a string literal that describes the reason for failure, as demonstrated in Listing 2.
public class AssertDemo
{
public static void main(String[] args)
{
int x = -1;
assert x >= 0: "x < 0";
}
}
Compile Listing 2 (javac AssertDemo.java) and run it with assertions enabled (java -ea AssertDemo). This time, you should observe the following slightly expanded output, which includes the reason for the thrown AssertionError:
Exception in thread "main" java.lang.AssertionError: x < 0
at AssertDemo.main(AssertDemo.java:6)
For either example, running AssertDemo without the -ea (enable assertions) option results in no output. When assertions are not enabled, they are not executed, although they are
still present in the classfile.
Assertions are often used to test a program's preconditions and postconditions:
You can enforce preconditions on public constructors and methods by making explicit checks and throwing exceptions when necessary. For private helper methods, you can enforce preconditions by specifying assertions. Consider Listing 3.
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
class PNG
{
/**
* Create a PNG instance, read specified PNG file, and decode
* it into suitable structures.
*
* @param filespec path and name of PNG file to read
*
* @throws NullPointerException when <code>filespec</code>
is
* <code>null</code>
*/
PNG(String filespec) throws IOException
{
// Enforce preconditions in non-private constructors and
// methods.
if (filespec == null)
throw new NullPointerException("filespec is null");
try (FileInputStream fis = new FileInputStream(filespec))
{
readHeader(fis);
}
}
private void readHeader(InputStream is) throws IOException
{
// Confirm that precondition is satisfied in private
// helper methods.
assert is != null : "null passed to is";
}
}
public class AssertDemo
{
public static void main(String[] args) throws IOException
{
PNG png = new PNG((args.length == 0) ? null : args[0]);
}
}
The PNG class in Listing 3 is the minimal beginning of a library for reading and decoding PNG (portable network graphics) image files.
The constructor explicitly compares filespec with null, throwing NullPointerException when this parameter contains null. The point is to enforce the precondition that filespec not contain null.
It's not appropriate to specify assert filespec != null; because the precondition mentioned in the constructor's Javadoc wouldn't (technically) be honored when assertions were disabled.
(In fact, it would be honored because FileInputStream() would throw NullPointerException, but you shouldn't depend on undocumented behavior.)
However, assert is appropriate in the context of the private readHeader() helper method, which will be completed eventually to read and decode a PNG file's 8-byte header. The precondition that is always be passed a nonnull value will always hold.
Postconditions are typically specified via assertions, regardless of whether or not the method (or constructor) is public. Consider Listing 4.
public class AssertDemo
{
public static void main(String[] args)
{
int[] array = { 20, 91, -6, 16, 0, 7, 51, 42, 3, 1 };
sort(array);
for (int element: array)
System.out.printf("%d ", element);
System.out.println();
}
private static boolean isSorted(int[] x)
{
for (int i = 0; i < x.length-1; i++)
if (x[i] > x[i+1])
return false;
return true;
}
private static void sort(int[] x)
{
int j, a;
// For all integer values except the leftmost value ...
for (int i = 1; i < x.length; i++)
{
// Get integer value a.
a = x[i];
// Get index of a. This is the initial insert position, which is
// used if a is larger than all values in the sorted section.
j = i;
// While values exist to the left of a's insert position and the
// value immediately to the left of that insert position is
// numerically greater than a's value ...
while (j > 0 && x[j-1] > a)
{
// Shift left value -- x[j-1] -- one position to its right --
// x[j].
x[j] = x[j-1];
// Update insert position to shifted value's original position
// (one position to the left).
j--;
}
// Insert a at insert position (which is either the initial insert
// position or the final insert position), where a is greater than
// or equal to all values to its left.
x[j] = a;
}
assert isSorted(x): "array not sorted";
}
}
Listing 4 presents a sort() helper method that uses the insertion sort algorithm to sort an array of integer values. I've used assert to check the postcondition of x being sorted before sort() returns to its caller.
The example in Listing 4 demonstrates an important characteristic of assertions, which is that they're typically expensive
to execute. For this reason, assertions are usually disabled in production code. In Listing 4, isSorted() must scan through the entire array, which can be time-consuming in the case of a lengthy array.
In addition to the Java Concurrency Utilities (profiled in June 2013 for this series), Java 5 added eight new language features: generics, typesafe enums, annotations, autoboxing and unboxing, enhanced for loop, static imports, varargs, and covariant return types. I'll cover all of these Java 5 features over the next two articles, starting here with generics.
Generics is a suite of language features that allow types or methods to operate on objects of various types while providing compile-time
type safety. Generics address the problem of java.lang.ClassCastExceptions thrown at runtime due to code that is not type safe.
java.util.concurrent.
java.time classes you're most likely to need.