Summary
Even if your Java class uses native methods, you can maintain portability by providing fallback methods that are called if the run-time system cannot locate or use the appropriate dynamic library. (550 words)
By Nick Efford
Java is great fun to use, but there are times when it is too slow. My field of interest, image processing, is a case in point: The frequent array accessing and intensive calculation performed in many image processing operations can have a significant impact on the performance of Java code. On my machine, a fairly ordinary Silicon Graphics Indy, a 3-by-3 convolution of a 512-by-512 image is more than 40 times slower in Java than in C++. Just-in-time (JIT) compilers and hardware accelerators should eventually improve matters, but in the meantime there is another solution: native methods.
Of course, the main problem with using native methods is that they make your Java code applet-unfriendly and non-portable; in effect, you lose the very features that make Java such an interesting and important language in today's network-centric computing environments. In many situations, the best option may simply be to forget about Java and develop your application in a language better suited to the problem domain. If you need to use Java, however, it is possible to use native methods in classes without sacrificing portability, through the use of fallbacks.
The basic idea is this: For each native method in your class, you supply an equivalent non-native method that will be executed if the system cannot locate or load the dynamic library containing the native method code.
Your class will obviously need some means of registering whether native methods are available, and this can be done by using a boolean class variable. This variable is set to true or false in the static block of code that attempts to load the dynamic library associated with your class:
public class Convolver { private static boolean _native; static { try { System.err.println("Convolver: loading dynamic library..."); System.loadLibrary("Convolver"); _native = true; } catch (UnsatisfiedLinkError e) { System.err.println("Convolver: no library found - " + "using fallback methods..."); _native = false; } catch (Exception e) { System.err.println("Convolver: cannot load library - " + "using fallback methods..."); _native = false; } } ... }In the above example,
_native
is used to flag the
availability (or lack) of native methods. It is set to true if the
call to System.loadLibrary succeeds. If, however, the
named library cannot be found -- because the library does not exist
on the user's system, or because LD_LIBRARY_PATH or its equivalent is
not set correctly -- then an UnsatisfiedLinkError
is
thrown. We catch this and set _native
to false (and also
print a warning to the user that fallbacks will be used instead of native
methods).
The second catch
block in the above example makes our class
applet-friendly, because it allows us to recover from exceptions thrown by a
Web browser whose security manager prohibits the use of dynamic libraries.
Again, we print a warning message on stream System.err
and set
_native
to false.
Note that class users should not be allowed to invoke native methods and their associated fallback methods directly; it is up to the class itself to decide, when it is loaded into memory, whether to use native or fallback code. Consequently, we make the native methods and their fallbacks private and supply a public method that simply invokes the native method or the fallback, depending on the value of our boolean class variable:
public void convolve() { if (_native) nativeConvolve(); else fallbackConvolve(); } private native void nativeConvolve(); private void fallbackConvolve() { ... }In this example, a convolution operation can be performed either by native method
nativeConvolve
or by fallback method
fallbackConvolve
. The distinction between these two methods
is irrelevant to the class user, who simply invokes convolve
to perform the operation. If the dynamic library has been installed, the
user gets the benefits of faster execution; if the dynamic library is
unavailable, the operation can still be carried out, albeit more slowly.
That's all there is to it! Once you've written and compiled your class, you add the native method support in the normal way. (See the current version of Sun's Java Tutorial for an explanation of how to do this.)
JavaWorld also features a Java
Questions & Answers column! Send your Java language questions to
javaqa@javaworld.com
now.
About the author
Nick Efford is a lecturer at the School
of Computer Studies at the
University of Leeds, U.K. Nick's research has been concerned mainly with the
knowledge-based segmentation of medical images and the identification of
objects of interest, using 2-D and 3-D models of object shape. Nick
currently teaches image processing at the School of Computer Studies.
We would also like to pass on your Java Tips to the rest of the Java world. Start writing up your coolest tips and tricks now so that you can send them in -- and be eligible for JavaWorld's "Java Tip of the Week" contest.
If your Java tip is chosen as JavaWorld's Java Tip of the Week, you'll be awarded a prized JavaWorld T-shirt and 10,080 minutes of fame and prestige. Send your Java tips and tricks to javatips@javaworld.com.
If you have problems with this magazine, contact
webmaster@javaworld.com
URL: http://www.javaworld.com/javaworld/javatips/jw-javatip13.html
Last updated: 15 August 1996