Avoiding Platform Depedent Code (Java) – MIT 6.0055 min read
Avoiding Platform Depedent Code
Although Java is considered platform independent (i.e. compiled Java code can execute on different operating systems without re-compiling), you can still write Java code that is platform dependent. The compiler won’t complain when you write platform dependent code, but users on different system will not be happy when they try to run your program.
To ensure the staff can run and grade all your code, avoid the following platform dependence issues. You will be held responsible for all issues discussed on this page!
Windows and Unix systems use different conventions for the file separator (“\” in Windows, “/” in Unix, ). Java will usually make the correct conversions if you use the Unix file separator “/” in relative paths.
Alternatively, you can use the file.separator property or File fields when writing path names:
// Using System properties String separator = System.getProperty( "file.separator" ); // Using File field (String) seperator = File.separator; // Using File field (char) char separatorChar = File.separatorChar;
Windows and Unix systems use different conventions for the path separator (“;” in Windows, “:” in Unix, ). Path separators are used to separate a list of paths, for example:
(Windows) C:\Program Files\Java\jre6\bin;C:\MATLAB;C:\Some\Other\Path\bin; (Unix) /usr/bin:/usr/local/bin:/home/billybob/xmlbeans/bin
You can use the path.separator property, or File fields when writing path names:
// Using System properties String pathSeparator = System.getProperty( "path.separator" ); // Using File variable (String) pathSeperator = File.pathSeparator; // Using File variable (char) char pathSeparatorChar = File.pathSeparatorChar;
Windows and Unix systems use different conventions for root directories (“C:\” in Windows, “/” in Unix, ). You should generally avoid ever using roots to specify a path in your program. You can do this by using relative path names instead. For example:
(Absolute Path) C:\Documents and Settings\billybob\My Documents\data\foo.txt (Relative Path) data/foo.txt
The relative path will find the “foo.txt” file assuming you run the program the the “My Documents” directory.
However, if you still need a list of roots, use the File.listRoots( ) method:
File  roots = File.listRoots( );
Whenever you want to create a temporary file, you should try creating a file in the current directory (i.e. the directory where you ran your program from), or use the File.createTempFile( String prefix, String suffix ) method:
// Create two temporary files f1 = File.createTempFile( "6005file", ".txt" ); f2 = File.createTempFile( "6005file", ".txt" ); // Ensures they are removed when program exits f1.deleteOnExit( ); f2.deleteOnExit( );
Case Sensitive Names
Not all operating systems have case senstive file systems. For example, Windows considers “FOO.txt” and “foo.txt” as the same. So avoid using file names that are case sensitive.
Windows and Unix systems use different characters to represent the start of a new line. In 6.005, we require that all required output for an assignment use the Unix newline character: ‘\n’.
This means if an assignment requires you to write to a file, you should make sure your program uses ‘\n’ in the file. Do not worry about output you use for personal debugging.
You can ensure your program uses ‘\n’ by setting the line.separator property. After setting this property, calls to methods like println() from PrintStream will use the value set for line.separator. Note, that System.out.println() will still use your system’s default println. Do not worry about this.
PrintStream before, after; // Creating printstream BEFORE setting property will NOT // use the custom newline =( before = new PrintStream( "foo.txt" ); // Setting system property for newline System.setProperty( "line.separator", "\n" ); // Creating the printstream AFTER setting the property // uses the custom newline =) after = new PrintStream( "baz.txt" ); before.println( "This will NOT use the newline we set in the properties" ); after.println( "This will work as expected" );
In Java, you can access environment variables using the System.getenv() method. You should avoid doing this if the same value is available in a system property. For example, if the operating system provides a user name, it will be in the system property user.name.
String username; // AVOID username = System.getenv( "USERNAME" ); // Better username = System.getProperty( "user.name" );
Even when using Swing, there may be many subtle differences in the appearance of your UI on different platforms. Some general guidelines:
- Avoid using the native LookAndFeel. The native look and feel can be drastically different (especially in the case of OS X) between platforms. Stick to cross-platform look and feels.
- Do not rely on specific fonts, unless you bundle them with your application. Try to use font families, such as serif, sans-serif, and monospace. If you really want your custom font in your application, bundle the font with your code, so that the code loads the font.
- Avoid setting absolute values for positions and sizes in your GUI. Try to use relative values as much as possible. Although 100 pixels may seem small on your screen, it could be fairly large on someone with a smaller display. This is especially a problem when dealing with fonts! Do not use absolute positioning to align elements around text!
- Test it out on different systems. This is always tedious, but never hurts. At least test the UI on each of your group members’ computers. If you deploy your application into a JAR, then you can easily test it on Athena and other computers.
In Unix, attempting to bind a socket to a port less than 1024 will cause a permission exception in Java. Do not bind a socket to a local port below 1024.