Some older languages such as C, PL/I, and C++ provide a feature known as conditional compilation. Conditional compilation means that parts of the program can be included or excluded at compile time based upon some condition. One thing it’s often used for is to include or exclude debugging print statements. When the program appears to be working, the developer is struck by a fit of hubris and removes all the error checking :-). A more common rationale is that the developer wants to make the finished program smaller -- a worthy goal -- or run faster by removing conditional statements.
Although Java lacks any explicit conditional compilation, there is a
kind of conditional compilation implicit in the language. All Java
compilers must do flow
analysis
to ensure that all paths to a
local variable’s usage pass through a statement that assigns it
a value first, that all returns from a function pass out via
someplace that provides a return value, and so on. Imagine what the
compiler will do when it finds an if
statement
whose value is known to be false at compile
time. Why should it even generate code for the
condition? True, you say, but how can the results of an
if
statement be known at compile time? Simple:
through final
boolean
variables.
Further, if the value of the if
condition is known
to be false, then the body of the if
statement
should not be emitted by the compiler either. Presto -- instant
conditional compilation!
// IfDef.java final boolean DEBUG = false; System.out.println("Hello, World "); if (DEBUG) { System.out.println("Life is a voyage, not a destination"); }
Compilation of this program and examination of the resulting class
file reveals that the string “Hello” does appear, but the
conditionally printed epigram does not. The entire
println
has been omitted from the class file. So
Java does have its own conditional compilation mechanism.
darian$ jr IfDef jikes +E IfDef.java java IfDef Hello, World darian$ strings IfDef.class | grep Life # not found! darian$ javac IfDef.java # try another compiler darian$ strings IfDef.class | grep Life # still not found! darian$
What if we want to use debugging code similar to this, but have the
condition applied at runtime? We can use
System.properties
(Section 2.3)
to fetch a variable. Section 1.12 uses my
Debug
class as example of a class whose entire
behavior is controlled this way.
But this is as good a place
as any to interject about another
feature, inline code generation. The
C world has a language keyword _ _inline
, which is
a hint to the compiler that the function (method) is not needed
outside the current source file. Therefore, when the C compiler is
generating machine code, a call to the _ _inline
function can be replaced by the actual method body, eliminating the
overhead of pushing arguments onto a stack, passing control,
retrieving parameters, and returning values. In Java, making a method
final enables the compiler to know that it can be inlined, or emitted
in line. This is an optional optimization that the compiler is not
obliged to perform, but may for efficiency.
3.15.137.59