Consider the program:
public class Test {
public static void main(String[] args) {
if (Arrays.asList(args).contains("--withFoo")) {
use(new Foo());
}
}
static void use(Foo foo) {
// do something with foo
}
}
Is Foo required in the runtime classpath if the program is launched without arguments?
Research
The Java Language Specification is rather vague when Linkage Errors are reported:
This specification allows an implementation flexibility as to when linking activities (and, because of recursion, loading) take place, provided that the semantics of the Java programming language are respected, that a class or interface is completely verified and prepared before it is initialized, and that errors detected during linkage are thrown at a point in the program where some action is taken by the program that might require linkage to the class or interface involved in the error.
My Tests indicate that LinkageErrors are only thrown when I actually use Foo
:
$ rm Foo.class
$ java Test
$ java Test --withFoo
Exception in thread "main" java.lang.NoClassDefFoundError: Foo
at Test.main(Test.java:11)
Caused by: java.lang.ClassNotFoundException: Foo
at java.net.URLClassLoader$1.run(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 1 more
Can this behaviour be relied upon? Or is there any mainstream JVM that links unused code? If so, how can I isolate unused code such that it is only linked if needed?