★ wanayoo — archive 1999 http://java.oreilly.com/bite-size/java_0999.htmlNouvelle recherche | Portail wanayoo

BITE-SIZE JAVA

Search Product
Index Press
Room

Perl Center
---
Java Center
---
Web Center
---
Linux Center
---
UNIX Center
---
Windows Center
---
Oracle Center
---
Sys Admin Center
---
Security
Center
---
C/C++ Programming Center
---
Design Center
---
O'Reilly Software Online
---
Online
Books Center
---
Web-Based Training
---

O'Reilly

O'Reilly Java Resource Center

Bite-Size Java Java Application Etiquette
by Jonathan Knudsen

Jonathan Knudsen

Java is a great programming language because you cannot make certain kinds of stupid mistakes. Three Java language features force your code to be more safe and more robust than in other languages:
 

  1. The garbage collector saves you the trouble of keeping track of the memory you're using. Memory management, in languages like C and C++, is the hobgoblin that causes many, many application bugs.

  2. The lack of explicit pointers means you won't ever write on memory that doesn't belong to you.

  3. Java's exception mechanism forces you to properly acknowledge that things may go wrong.
That's just peachy. But it's still possible to write sloppy programs, even in Java. I'm not talking about questions of object oriented design, syntax, commenting, and code clarity. I'm talking about things like releasing resources when you're through with them, shutting down threads you no longer want, or closing files you're not using.

JVM Hogs

Usually, your application runs in a single Java Virtual Machine (JVM) and you don't have to worry about keeping the JVM clean. Suppose, for example, that you write an application called Friendly. To run it, you'll type this at a command line somewhere:
java Friendly
This command fires up the JVM, which runs as a process in whatever operating system (OS) you're running. The Friendly application has the entire JVM to itself.

But that's just how things work today. Java is spreading like wildfire. It's very likely that Java will find its way into operating systems, a more intimate relationship than just having a JVM as a process. I would be surprised if Linux did not end up with an embedded JVM sometime soon.

Having a JVM embedded in the OS is a whole new ball game. On the one hand, it means you can run Java applications really fast because you don't have to start up the JVM every time you want to run the application. On the other hand, it really changes your perspective on how applications should behave. Now, a single JVM is shared by multiple applications.

(An intermediate step is a Java application runner, which is simply a program that runs other Java programs. I've written a skeleton of such a program, which highlighted the issues of running more than one application in a single JVM.)

The Dark Side of System.exit()

Most Java applications are written so that when the user quits, the application calls System.exit() to shut down the JVM. System.exit() is the proper way to shut down the JVM, but you are probably relying on it to shut down your application as well. System.exit() does all sorts of things that you should really be doing explicitly in your application:
  • It gets rid of open windows.
  • It closes any open files.
  • It shuts down any open network sockets.
  • It shuts down any threads you might have left running.
To make your application run correctly in a multiple-application JVM, you'll have to clean up yourself. In fact, you probably won't be allowed to call System.exit(), as this would shut down the entire JVM, including its other running applications. In this case, calling System.exit() will just result in a SecurityException and none of your application will be cleaned up.

Do You Do Windows?

The following code simply creates and displays a JFrame. When you click on the frame window's close icon, the window goes away:

import java.awt.event.*;

import javax.swing.*;

public class Unfriendly {
  public static void main(String[] args) {
    final JFrame f = new JFrame("Unfriendly");
    f.setSize(200, 200);
    f.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent we) {
        System.exit(0);
      }
    });
    f.setVisible(true);
  }
}

It works fine as a standalone application, in its own JVM. But in a multiple-application environment, the call to System.exit() will simply generate a SecurityException. The window itself won't go away.

A nicer application would close its own window, like this:

import java.awt.event.*;

import javax.swing.*;

public class LessUnfriendly {
  public static void main(String[] args) {
    final JFrame f = new JFrame("LessUnfriendly");
    f.setSize(200, 200);
    f.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent we) {
        f.dispose();
        System.exit(0);
      }
    });
    f.setVisible(true);
  }
}

But it still generates a SecurityException. A truly nice program closes its own windows and doesn't assume that it can shut down the JVM. The following example shows how you can explicitly catch the SecurityException that may be thrown from System.exit():

import java.awt.event.*;

import javax.swing.*;

public class Nice {
  public static void main(String[] args) {
    final JFrame f = new JFrame("Nice");
    f.setSize(200, 200);
    f.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent we) {
        f.dispose();
        try { System.exit(0); }
        catch (SecurityException se) {}
      }
    });
    f.setVisible(true);
  }
}

Files, Sockets, and Threads

The same type of thinking can be applied to files and network connections. Don't assume that they'll get cleaned up by System.exit(); explicitly close them yourself. This is good practice anyhow, as you don't want to overburden your system with open files or sockets.

Similarly, if your program creates any threads, it should explicitly shut them down when it's done. Usually you can accomplish this by calling the interrupt() method on the running threads.

File Locations

One final wrinkle of applications that run in a multiple-application JVM has to do with loading files. Your application may load configuration information, images, and sounds from disk files. The following application, for example, expects to read configuration information from a file called preferences.txt, found in the same directory as the application itself:

import java.io.*;

public class Lost {
  public static void main(String[] args) {
    try {
      String filename = "preferences.txt";
      Reader in = new FileReader(filename);
      // ...
      // Read preferences data.
      // ...
      in.close();
    }
    catch (IOException ioe) { System.out.println(ioe); }
  }
}

Run this in its own JVM, and everything is fine. But you're making a big assumption: you're assuming that the current directory of the entire JVM is the same directory that contains your application. If, instead, you run the Lost application from inside somebody else's JVM, Lost will not be able to find its preferences file.

One solution, of course, is to use absolute pathnames. But this is usually a bad idea, particularly in a cross-platform language like Java. Pathname conventions vary from OS to OS, so there's no guarantee that an absolute path that works on one OS will work on another.

A better way (and what we really wanted in the first place) is to specify the file's path relative to the location of the application itself. Fortunately, Java provides a way to do this. The Class class has a method called getResourceAsStream(), which finds a file relative to a class file. It's easier than it sounds; here's an example:

import java.io.*;

public class Found {
  public static void main(String[] args) {
    try {
      String filename = "preferences.txt";
      InputStream rawIn = Found.class.getResourceAsStream(filename);
      Reader in = new InputStreamReader(rawIn);
      // ...
      // Read preferences data.
      // ...
      in.close();
    }
    catch (IOException ioe) { System.out.println(ioe); }
  }
}

This technique is highly portable. It even works for files inside a JAR.

Be Prepared for Revolution

Let's just assume that the JVM will work its way into the OS, instead of running as a process on top of the OS. When this evolution happens, you're not going to want to rework your existing applications. If you follow the guidelines presented in this article, you should ready when the revolution comes. Remember, the mantra is "Clean up!"

Download the source code.


Jonathan Knudsen is an author and developer at O'Reilly & Associates. He is the author of Java Cryptography, Java 2D Graphics, and LEGO® MINDSTORMS Robots (due out in October 1999).


O'Reilly Home | O'Reilly Bookstores | How to Order | O'Reilly Contacts
International | About O'Reilly | Affiliated Companies

© 1999, O'Reilly & Associates, Inc.