Good Java Style

Thornton Rose

Published as "Good Java Style: Part 1", 2/22/2001, and "Good Java Style: Part 2", 2/28/2001, Gamelan.com.

Copyright © 2001, Thornton Rose.

Thanks to April Rose, David Thurmond, and John Straw for their reviews.


Having worked as a software developer and consultant for many years, I have seen a large amount of code in a variety of programming languages. It has run the gamut from elegant to ugly, and unfortunately much of it has been ugly. With this article, I hope to persuade you, and my fellow developers, that we should give as much attention to the style of our code as we give to the user interface and other visible parts of an application. I will explain why we should care about how our code looks, then illustrate elements of good style for Java.

Why Style Matters

Even though Java is used to write programs rather than prose, it is still used to express thoughts and ideas. And, in addition to conveying information, those thoughts and ideas must actually do something. Worrying about good style may seem like a waste of time, but it behooves us to write our code such that the thoughts and ideas it expresses are exceptionally clear.

Here are several reasons for using good style:

Writing code with good style also provides the following benefits:

General Guidelines

Writing Java with good style is not hard, but it does require attention to detail. Here are some general guidelines to follow:

Tabs vs. Spaces

Tabs vs. spaces is one of several religious issues related to writing code, and I am not going to suggest that there is only one right way. I espouse using spaces, because it ensures that my code will look the same in my editor as it does in your editor, and vice versa. If you feel that using spaces instead of tabs just ain't right, then by all means use tabs.

Braces and Indentation

Indent style, or the placement of braces ("{" and "}") and the associated indentation of code, is another of the religious issues related to writing code. There are several indent styles common to C-style languages like Java, and I am not going to suggest that one of them is superior. In most of the example code in this article I use what is usually referred to as K&R style. If you don't like K&R, by all means use another style.

Source Files

There are many ways that a Java source file can be organized. Here is one that works well:

  1. File header comment (optional).
  2. Package declaration.
  3. Blank line or other separator.
  4. Import statements.
  5. Blank line or other separator.
  6. Class(es).

Example 1 - Bad File Organization
package org.rotpad;
import java.awt.*;
import javax.swing.event.*;
import org.javacogs.*;
import javax.swing.*;
import java.awt.event.*;
class Foo {
   ...
}
public class RotPad extends JFrame {
   ...
}

Example 2 - Good File Organization
package org.rotpad;

// Java classes
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

// JavaCogs classes
import org.javacogs.*;

/**
 * RotPad is a simple GUI application for performing rotation ciphers on plain
 * text.
 *
 * @author Thornton Rose
 * @version 1.0
 */
public class RotPad extends JFrame {
   ...
}

//-----------------------------------------------------------------------------

/**
 * Foo is ...
 *
 * @author Thornton Rose
 * @version 1.0
 */
class Foo {
   ...
}

Import Statements

A complex class can have a large number of imports, which can get unruly, especially if you prefer to import individual classes instead of whole packages (e.g. java.awt.*). To get a handle on the imports, organize them as follows:

Be sure to comment the third-party and application classes, particularly those that do not have obvious names. Use end-of-line comments, or put a comment at the beginning of the section. Also, if you really want to be a perfectionist, order each group of imports alphabetically.

Example 1 - Bad Import Style
import java.util.*;
import javax.swing.*;
import java.awt.event*;
import com.gensym.com.*;
import javax.swing.table.*;
import com.pv.jfcx.*;
import java.awt.*;
import com.melthorn.util.*;

Example 2 - Good Import Styles
import java.awt.*;
import java.awt.event*;
import java.util.*;
import javax.swing.table.*;
import com.gensym.com.*;     // BeanXporter
import com.pv.jfcx.*;        // ProtoView
import com.melthorn.util.*;  // Utilities
// Java classes
import java.awt.*;
import java.awt.event*;
import java.util.*;
import javax.swing.table.*;

// BeanXporter
import com.gensym.com.*;

// ProtoView GUI components
import com.pv.jfcx.*;

// Application classes
import com.melthorn.util.*;

Classes

Organizing a Java source file without organizing the classes in it would not gain you much in the way of style. Here's how to organize the classes in your source files:

  1. Javadoc comment or other header comment.
  2. Class declaration.
  3. Field declarations.
  4. Blank line or other separator.
  5. Constructors.
  6. Blank line or other separator.
  7. Methods, except main(), grouped logically.
  8. Blank line or other separator.
  9. Inner classes.
  10. Blank line or other separator.
  11. main()
Example 1 - Bad Class Style
// RotPad -- GUI app. for ROT ciphering
public class RotPad extends JFrame {
   private static final String TRANSFORM_ROT13    = "ROT13";
   private static final String TRANSFORM_ROT13N5  = "ROT13N5";
   private static final String TRANSFORM_ROTASCII = "ROT-ASCII";

   private void jbInit() throws Exception {
      ...
   }

   public static final String TITLE   = "RotPad";
   public static final String VERSION = "1.0";

   public static void main(String[] args) {
      ...
   }

   public RotPad() {
      ...
   }

   private JPanel jPanel1 = new JPanel();
   private JPanel jPanel2 = new JPanel();
   private BorderLayout borderLayout1 = new BorderLayout();
   ...
}

Example 2 - Good Class Style
/**
 * RotPad is a simple GUI application for performing rotation ciphers on plain
 * text.
 *
 * @author Thornton Rose
 * @version 1.0
 */
public class RotPad extends JFrame {
   // Public constants

   public static final String TITLE   = "RotPad";
   public static final String VERSION = "1.0";

   // Private constants

   private static final String TRANSFORM_ROT13    = "ROT13";
   private static final String TRANSFORM_ROT13N5  = "ROT13N5";
   private static final String TRANSFORM_ROTASCII = "ROT-ASCII";

   // GUI components [JBuilder generated]

   private BorderLayout borderLayout1 = new BorderLayout();
   private JPanel jPanel1 = new JPanel();
   private JPanel jPanel2 = new JPanel();
   ...

   /**
    * Construct a new instance of this class.
    */
   public RotPad() {
      ...
   }

   /**
    * Initialize UI components. [JBuilder generated]
    */
   private void jbInit() throws Exception {
      ...
   }

   ...

   //--------------------------------------------------------------------------

   /**
    * Start the application.
    */
   public static void main(String[] args) {
      ...
   }
}

Field Declarations

Some classes have a large number of fields, which can get difficult to maintain if they are not organized well. Organize them as follows:

  1. Public contstants (final and static final).
  2. Public variables.
  3. Protected constants.
  4. Protected variables.
  5. Package constants.
  6. Package variables.
  7. Private constants.
  8. Private variables.

Additionally, use the following guidelines for writing field declarations:

Example 1 - Bad Field Style
   public class CustomerSearchDialog extends JDialog {
      private JLabel firstNameLabel = new JLabel();
      private JLabel lastNameLabel = new JLabel();
      public static final RESULT_SELECT = 1;
      private Vector results = new Vector(); // Search results.
      private DefaultTableModel tableModel = new DefaultTableModel();
      public static final RESULT_CANCEL = 0;
      // ...
   }

Example 2 - Good Field Style
/**
 * ...
 */
public class CustomerSearchDialog extends JDialog {
   /**
    * Indicates that search was cancelled; returned by showDialog() when
    * user clicks cancel button.
    */
   public static final RESULT_CANCEL = 0;

   /**
    * Indicates that a customer was selected; returned by showDialog() when
    * user clicks select button.
    */
   public static final RESULT_SELECT = 1;

   private Vector            results    = new Vector();             // Search results.
   private DefaultTableModel tableModel = new DefaultTableModel();  // Grid model.

   // GUI fields. [JBuilder]

   private JLabel firstNameLabel = new JLabel();
   private JLabel lastNameLabel = new JLabel();
   // ...
}

Method Declarations

Use the following guidelines for writing method declarations:

Example 1 - Bad Method Style
public int getTypeCount (String custType)
   {
   ...
   }
static public getInstance(){ ... };
public void showRange()
   throws RangeException {
   ...
}

Example 2 - Good Method Styles
/**
 * Return the single instance of this class.
 */
public static CalculationEngine getInstance() {
   return instance;
}

/**
 * Calculate the consumption coefficient.
 */
public float calculateConsumptionCoefficient(int base, float variance,
      int iterations) throws RangeException {
   // ...
}
/**
 * Calculate the consumption coefficient.
 */
public float calculateConsumptionCoefficient(
      int base,
      float variance,
      int iterations)
   throws RangeException
{
   // ...
}
/**
 * Calculate the consumption coefficient.
 */
public float calculateConsumptionCoefficient(int base,
                                             float variance,
                                             int iterations)
   throws RangeException
{
   // ...
}

Blocks and Statements

Use the following guidelines for writing blocks and statements:

Variables used in for loops are the exception to putting variables at the beginning of a block. The loop variable(s) may be declared in the initialization part of the for statement, e.g. for (int i = 0; ...).

Putting a comment at the end of a block can help you track down accidentally deleted closing braces. Finding those in a large source file can sometimes drive you nearly crazy.

Example 1 - Bad Block Style
try{
   for(int i=0;i<5;i++){
      ...
      }
   int threshhold=calculateThreshhold();
   float variance=(threshhold*2.8)-1;
   int c=0;
   if (threshhold<=15) c=calculateCoefficient();
   switch(c){
   case 1: setCeiling(c*2); break;
   case 2: setCeiling(c*3); break;
   else: freakOut();
   }
}catch(Exception ex){ ... }

Example 2 - Good Block Style
try {
   int   threshhold  = 0;
   float variance    = 0.0;
   int   coefficient = 0;

   // Prepare 5 cycles.

   for (int i = 0; i < 5; i ++){
      prepareCycle(i);
   }

   // Calculate the threshhold and variance.

   threshhold = calculateThreshhold();
   variance = (threshhold * 2.8) - 1;

   // If the threshhold is less than the maximum, calculate the coefficient.
   // Otherwise, throw an exception.

   if (threshhold <= MAX_THRESHHOLD) {
      coefficient = calculateCoefficient();
   } else {
      throw new RuntimeException("Threshhold exceeded!");
   }

   // Set the ceiling based on the coefficient.

   switch (coefficient) {
      case 1:
         setCeiling(coefficient * 2);
         break;

      case 2:
         setCeiling(coefficient * 3);
         break;

      else:
         freakOut();
   } // end switch
} catch(Exception ex) {
   ...
} // end try

Comments

There are two type of comments that you can put in your Java code: Javadoc comments (also called documentation comments) and implementation comments. Javadoc comments can be extracted by the javadoc tool to produce API documentation. Implementation comments are those comments that explain the how and why of the code. Use the following guidelines for commenting your Java code:

Also, keep in mind that good comments are helpful; bad comments are a nuisance.

Example 1 - Bad Comment Style
// applyRotAscii() -- Apply ASCII ROT
private void applyRotAscii(){
   try{
      int rotLength = Integer.parseInt(rotationLengthField.getText().trim()); // get rot len
      RotAscii cipher = new RotAscii(rotLength); // new cipher
      textArea.setText(cipher.transform(textArea.getText())); // transform
   }catch(Exception ex){
      /* Show exception */
      ExceptionDialog.show(this, "Invalid rotation length: ", ex); }
}

Example 2 - Good Comment Style
/**
 * Apply the ASCII rotation cipher to the user's text. The length is retrieved
 * from the rotation length field, and the user's text is retrieved from the
 * text area.
 *
 * @author Thornton Rose
 */
private void applyRotAscii() {
   int      rotLength = 0;  // rotation length
   RotAscii cipher = null;  // ASCII rotation cipher

   try {
      // Get rotation length field and convert to integer.

      rotLength = Integer.parseInt(rotationLengthField.getText().trim());

      // Create ASCII rotation cipher and transform the user's text with it.

      cipher = new RotAscii(rotLength);
      textArea.setText(cipher.transform(textArea.getText()));

   } catch(Exception ex) {
      // Report the exception to the user.

      ExceptionDialog.show(this, "Invalid rotation length: ", ex);
   }
}

Conclusion

In conclusion, I have one final thought for you on the subject of code style. No matter what guidelines you follow, and no matter how fervent your beliefs about things like indent style, remember that when you write code your overall goal should be to make the code understandable and maintainable by someone else.

Related Links

References

  1. Java Code Conventions. Copyright © 1995-2000 Sun Microsystems, Inc.