Equivalent of #define in Java?

There's no way to do what you want from within Java. You could preprocess the Java source files, but that's outside the scope of Java.

Can you not abstract the differences and then vary the implementation?

Based on your clarification, it sounds like you might be able to create a factory method that will return either an object from one of the external libraries or a "stub" class whose functions will do what you would have done in the "not-available" conditional code.


Well, Java syntax is close enough to C that you could simply use the C preprocessor, which is usually shipped as a separate executable.

But Java isn't really about doing things at compile time anyway. The way I've handled similar situations before is with reflection. In your case, since your calls to the possibly-non-present library are scattered throughout the code, I would make a wrapper class, replace all the calls to the library with calls to the wrapper class, and then use reflection inside the wrapper class to invoke on the library if it is present.


As other have said, there is no such thing as #define/#ifdef in Java. But regarding your problem of having optional external libraries, which you would use, if present, and not use if not, using proxy classes might be an option (if the library interfaces aren't too big).

I had to do this once for the Mac OS X specific extensions for AWT/Swing (found in com.apple.eawt.*). The classes are, of course, only on the class-path if the application is running on Mac OS. To be able to use them but still allow the same app to be used on other platforms, I wrote simple proxy classes, which just offered the same methods as the original EAWT classes. Internally, the proxies used some reflection to determine if the real classes were on the class-path and would pass through all method calls. By using the java.lang.reflect.Proxy class, you can even create and pass around objects of a type defined in the external library, without having it available at compile time.

For example, the proxy for com.apple.eawt.ApplicationListener looked like this:

public class ApplicationListener {

    private static Class<?> nativeClass;

    static Class<?> getNativeClass() {
        try {
            if (ApplicationListener.nativeClass == null) {
                ApplicationListener.nativeClass = Class.forName("com.apple.eawt.ApplicationListener");
            }

            return ApplicationListener.nativeClass;
        } catch (ClassNotFoundException ex) {
            throw new RuntimeException("This system does not support the Apple EAWT!", ex);
        }
    }

    private Object nativeObject;

    public ApplicationListener() {
        Class<?> nativeClass = ApplicationListener.getNativeClass();

        this.nativeObject = Proxy.newProxyInstance(nativeClass.getClassLoader(), new Class<?>[] {
            nativeClass
        }, new InvocationHandler() {

            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                String methodName = method.getName();

                ApplicationEvent event = new ApplicationEvent(args[0]);

                if (methodName.equals("handleReOpenApplication")) {
                    ApplicationListener.this.handleReOpenApplication(event);
                } else if (methodName.equals("handleQuit")) {
                    ApplicationListener.this.handleQuit(event);
                } else if (methodName.equals("handlePrintFile")) {
                    ApplicationListener.this.handlePrintFile(event);
                } else if (methodName.equals("handlePreferences")) {
                    ApplicationListener.this.handlePreferences(event);
                } else if (methodName.equals("handleOpenFile")) {
                    ApplicationListener.this.handleOpenFile(event);
                } else if (methodName.equals("handleOpenApplication")) {
                    ApplicationListener.this.handleOpenApplication(event);
                } else if (methodName.equals("handleAbout")) {
                    ApplicationListener.this.handleAbout(event);
                }

                return null;
            }

        });
    }

    Object getNativeObject() {
        return this.nativeObject;
    }

    // followed by abstract definitions of all handle...(ApplicationEvent) methods

}

All this only makes sense, if you need just a few classes from an external library, because you have to do everything via reflection at runtime. For larger libraries, you probably would need some way to automate the generation of the proxies. But then, if you really are that dependent on a large external library, you should just require it at compile time.

Comment by Peter Lawrey: (Sorry to edit, its very hard to put code into a comment)

The follow example is generic by method so you don't need to know all the methods involved. You can also make this generic by class so you only need one InvocationHandler class coded to cover all cases.

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    String methodName = method.getName();
    ApplicationEvent event = new ApplicationEvent(args[0]);
    Method method = ApplicationListener.class.getMethod(methodName, ApplicationEvent.class);
    return method.invoke(ApplicationListener.this, event);
}

In Java one could use a variety of approaches to achieve the same result:

  • Dependency Injection

  • Annotations

  • Reflection

The Java way is to put behaviour that varies into a set of separate classes abstracted through an interface, then plug the required class at run time. See also:

  • Factory pattern

  • Builder pattern

  • Strategy pattern