Conditional Compilation In Java

Java doesn't have conditional compilation, but you can ...

Exploit the Optimizer

You can get some of the effect by exploiting the optimiser. The JavaIdiom looks like this.

public class Assert {
public static final boolean isEnabled = true;
public static void assert( boolean c, String s ) {
...
}
}

void test( int x ) { if (Assert.isEnabled) Assert.assert( x >= 0, "test("+x+"): argument must be >= 0" ); }

Most (all?) Java compilers will optimise out the call to assert if isEnabled is set to false. Test() will become a null routine. It won't even evaluate the arguments to assert.

You should be able to replace Assert.isEnabled with any constant condition. In practise it can fail to optimise even for apparently trivial cases, like:

if (Assert.LEVEL >= Assert.FULL_LEVEL)
where LEVEL and FULL_LEVEL are static finals. This may vary with compiler. If the expression involves a function call, like:
if (Assert.isEnabled())
it cannot be optimised at compile time because of Java semantics. It might be optimised at link/load time but I wouldn't bet on it. If you really care about efficiency, test it on your target platform and/or use only the first, most simple case. The probability can be increased by declaring isEnabled() final.

This is not true conditional compilation because the compiler will check the body of the if for syntax and type errors. It is just an optimisation. However, sometimes it is all you need. You can build on it if you want, for example a class factory:

Database newDatabase() {
return Debug.isEnabled ?
new DebugDatabase?() : new FastDatabase?();
}
You can then put whatever code you like in DebugDatabase? and it will only get called when appropriate.

For further flexibility you can make the isEnabled flag not final during development, which allows you to turn debugging output on and off dynamically (from a command-line switch, for example). Only when you build the final version need you make the isEnabled flag final.

Use assert since Java 1.4

For what it's worth, JDK 1.4 has introduced a new keyword, assert, available with a command-line switch. This will affect us mostly in that JUnit 3.7 has marked its assert methods as deprecated; use assertTrue instead.

Use a preprocessor

If you need preprocessing (do you really do?), then why not use a preprocessor like m4?

ApacheAnt has a lot of useful "filters" to do special variable replacement and other preprocessing.

Use another language

Microsoft Visual J++ 6.0 has ConditionalCompilationInJava, only thet the language itself is not Java (guess why they call it J++ and not Java?). (Because Java is a Trademark of SunMicrosystems, and it requires to implements the exact specification of Java language -- ArturoTena)

Worth noting that there are plenty of supersets of java - jump, pizza, etc. - that give you conditional compilation, closures, templates, operator overloading and various other nonstandard bits and pieces that still generate jvm bytecode. And there are numerous compilers for other languages - prolog, scheme, etc. - that'll also output bytecode. Of course they don't have MicroSoft marketing them, so I guess they're not likely to get accepted any time soon.


JIT does it for us

For optimization, the final is the crucial signal to the JVM. But if that boolean is in a far-off class, can it really be optimized at compile time? It seems to me the compiler must always include the full unoptimized code, since Java treats classes as atomic. The value of isEnabled in the Assert class may change *after* we have compiled our Test class. Optimization is still possible, but only at runtime. It seems JIT does provide this: http://stackoverflow.com/questions/1813853/ifdef-ifndef-in-java#1813944


See also: JavaIdioms, EfficientContractsInJava.


CategoryJava


EditText of this page (last edited January 20, 2013) or FindPage with title or text search