Sun's motto, or core value proposition, for Java is "Write once, run anywhere." Java makes it easy to write portable programs, but Java programs do not automatically run successfully on any Java platform. To ensure portability, you must follow a few fairly simple rules that can be summarized as follows:
Portable Java code can use any methods in the core Java APIs, including methods implemented as native methods. However, portable code must not define its own native methods. By their very nature, native methods must be ported to each new platform, so they directly subvert the "Write once, run anywhere" promise of Java.
Calling the Runtime.exec() method to spawn a process and execute an external command on the native system is rarely allowed in portable code. This is because the native OS command to be executed is never guaranteed to exist or behave the same way on all platforms. The only time it is legal to use Runtime.exec() is when the user is allowed to specify the command to run, either by typing the command at runtime or by specifying the command in a configuration file or preferences dialog box.
Using System.getenv() is nonportable, without exception. The method has actually been deprecated for this reason.
Portable Java code must use only classes and interfaces that are a documented part of the Java platform. Most Java implementations ship with additional undocumented public classes that are part of the implementation, but not of the Java platform specification. There is nothing to prevent a program from using and relying on these undocumented classes, but doing so is not portable because the classes are not guaranteed to exist in all Java implementations or on all platforms.
The interfaces in the java.awt.peer package are part of the Java platform, but are documented for use by AWT implementors only. Applications that use these interfaces directly are not portable.
Portable code must not rely on features specific to a single implementation. For example, in a widely controversial move, Microsoft distributed a version of the Java runtime system that included a number of additional methods that were not part of the Java platform as defined by Sun. Legal action between Sun and Microsoft is pending because of this. Any program that depends on the Microsoft-specific extensions is obviously not portable to other platforms.
Just as portable code must not depend on implementation-specific features, it must not depend on implementation-specific bugs. If a class or method behaves differently than the specification says it should, a portable program cannot rely on this behavior, which may be different on different platforms.
Sometimes different platforms and different implementations may present different behaviors, all of which are legal according to the Java specification. Portable code must not depend on any one specific behavior. For example, the Java specification does not specify whether threads of equal priority share the CPU or if one long-running thread can starve another thread at the same priority. If an application assumes one behavior or the other, it may not run properly on all platforms.
Portable code can rely on standard extensions to the Java platform, but, if it does so, it should clearly specify which extensions it uses and exit cleanly with an appropriate error message when run on a system that does not have the extensions installed.
Any portable Java program must be complete and self-contained: it must supply all the classes it uses, except core platform and standard extension classes.
Portable Java code never defines classes in any of the system or standard extension packages. Doing so violates the protection boundaries of those packages and exposes package-visible implementation details.
A portable program contains no hardcoded file or directory names. This is because different platforms have significantly different filesystem organizations and use different directory separator characters. If you need to work with a file or directory, have the user specify the filename, or at least the base directory beneath which the file can be found. This specification can be done at runtime, in a configuration file, or as a command-line argument to the program. When concatenating a file or directory name to a directory name, use the File() constructor or the File.separator constant.
Different systems use different characters or sequences of characters as line separators. Do not hardcode "\n", "\r", or "\r\n" as the line separator in your program. Instead, use the println() method of PrintStream or PrintWriter, which automatically terminates a line with the line separator appropriate for the platform, or use the value of the line.separator system property.
The AWT event model changed dramatically between Java 1.0 and Java 1.1. Although it is often possible to mix these two event models in a program, doing so is not technically portable.
The previous rules are the focus of Sun's "100% Pure Java" portability certification program; you can find out more about this program and read more about the "Pure Java" requirements at http://java.sun.com/100percent/.
Copyright © 2001 O'Reilly & Associates. All rights reserved.