I recently discovered the "assert" statement in Java, and have been littering my software with them as I debug it. My initial instinct was to avoid making control flow statements just to handle assert statements, but then I realized that these control statements would probably be removed during a production build anyway, since their block would be empty. My impression is that they would be eliminated by the JIT compiler.
Unfortunately, I am working off of vague recollections of how the JIT compiler works, and cannot find appropriate documentation. The best I could find was this brief outline of the optimization process from IBM.
Before I get into the habit of implementing assertion-based tests, I wanted to know if there are best-practices to minimize their impact on performance. I'd hate to implement a bunch of tests only to find that their collective effect is to substantially decrease performance, even if individually their impact is negligible.
Can any of you tell me whether the following lines would be a drag on performance on a production build (with "assert" disabled, as is the default)?
for (T obj : Collection){
assert obj.someProperty();
}
For a bonus, what if I were something more complicated, including short-lived objects that are only used for the assertions?
TreeMap<Integer,T> map = new TreeMap<>();
int i = 0;
for (T obj : Collection){
map.put(i,obj);
assert obj.someProperty();
i++;
}
// assert something about map, then never use it again
Or a method whose only effect is to call "assert"?
Thanks in advance!
Relevant excerpts from Oracle's documentation of the "assert" statement:
These discuss how to remove assert from the class file, which is not exactly what I'm concerned about.
Removing all Trace of Assertions from Class Files Programmers developing applications for resource-constrained devices may wish to strip assertions out of class files entirely. While this makes it impossible to enable assertions in the field, it also reduces class file size, possibly leading to improved class loading performance. In the absence of a high quality JIT, it could lead to decreased footprint and improved runtime performance.
The assertion facility offers no direct support for stripping assertions out of class files. The assert statement may, however, be used in conjunction with the "conditional compilation" idiom described in the Java Language Specification, enabling the compiler to eliminate all traces of these asserts from the class files that it generates:
static final boolean asserts = ... ; // false to eliminate asserts
if (asserts) assert ;
and from the FAQ section:
Why not provide a compiler flag to completely eliminate assertions from object files? It is a firm requirement that it be possible to enable assertions in the field, for enhanced serviceability. It would have been possible to also permit developers to eliminate assertions from object files at compile time. Assertions can contain side effects, though they should not, and such a flag could therefore alter the behavior of a program in significant ways. It is viewed as good thing that there is only one semantics associated with each valid Java program. Also, we want to encourage users to leave asserts in object files so they can be enabled in the field. Finally, the spec demands that assertions behave as if enabled when a class runs before it is initialized. It would be impossible to offer these semantics if assertions were stripped from the class file. Note, however, that the standard "conditional compilation idiom" described in the Java Language Specification can be used to achieve this effect for developers who really want it.
You can make method calls from within an assert
, so the syntax I'd prefer is something like:
private static boolean testSomePropertyTrue(Collection<T> collection) {
boolean test = true;
for (T obj : collection){
test = test && obj.someProperty();
}
return test;
}
...
assert testSomePropertyTrue(collection);
This leaves no ambiguity about code being optimized out by the JIT, and when assertions are enabled will perform the same invariant checks.
As written, your second example will always create the TreeMap
, regardless of whether assertions are enabled. Wrapping the entire thing in an function and evaluating it as a single assert will completely eliminate that code path at run-time.
Like another answer to this question suggests, the assertions will leave behind bytecode regardless of whether they're enabled, but using the style shown above will deterministically prevent those codepaths from executing unless assertions are enabled.