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!

Files

  • Files Paths

    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;
    
  • Path Separator

    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;
    
  • Root Directories

    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( );
    
  • Temporary Files

    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.

Newlines

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" );

Environment Variables

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" );

GUI

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.

Sockets

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.