Programming Style in Java

Programming style, the way a program is formatted and the various parts are named, is as important to programming as prose style is to writing expository papers or fiction. Just as there are conventional prose forms there are conventional stylistic devices in computer programming. This document presents one set of conventions. These rules, a melding of suggestions I have read and developed over decades of programming, are strongly recommended to you. You are just getting started writing computer programs; follow these rules slavishly. When you have more experience you will be able to evaluate changes to your programming style. Understanding why these rules were chosen will help you learn how to develop your own style (over time).

Specific indentation and naming conventions change from programming shop to programming shop; if you ever need to change your code over to another style, there are automated tools to make that job easier.

There is one primary rule: be consistent. Where regularity can become monotony in prose, regularity in program text is a blessing to any human reader. This reminds us that all computer programs have two distinct intended audiences: the computer for execution and other programmers for extension or maintenance.

Perhaps there are two primary rules: be consistent and make sure your code compiles. This brings together the most basic concerns of human and machine readability of your code.

Comments

Comments are treated as spaces by the compiler. It pays no attention to what you put in the comment. This means that comments are solely for the the human reader of your code. You should use "enough" comments that they guide the human reader of your code through it. The question often arises "What is enough?" This section will attempt to answer that question by listing the types (and formats) of the various types of comments a program should contain.

One general note on comments: you can assume your audience is familiar with the programming language you are using. You don't need to add comments for things a programmer should know (the structure of a loop or the fact that int is the type for an integer).

Class Header Comment Every file defines a class; each class should begin with a header comment. This header comment serves as the introduction to the class for the human reader. It should include the name of the class, the name of the programmer, and a description of what it does. The following example is the header comment from the fictionalTwoSquaredCircles class:

/* 
   Program:    TwoSquaredCircles
   Author:     Brian C. Ladd
   
   Assignment: Lab 3 (REWRITE)

   Purpose:    This class draws two circles, one above the other. A circle
   is inscribed in each square and all four shapes are filled with
   different colors.

   Notes:      This class uses the "center finding" code provided in class;
   it is based on work presented in Willer's _Geometry for Clowns_.
*/

It is important to note that this header comment contains the name of the programmer, the name of the assignment, and a short description of what the whole class is supposed to do. The Notes section is optional but you should note the source of any code you are using (unless you wrote it for some other project).

Method Header Comments Before each named subprogram (the definition of a method) there should be a header comment similar to that at the beginning of a program. The comment should describe what the method does and describe what parameters are passed into the method.The following is an example for the (fictional) figureEight method:

/* figureEight
   Purpose: This method moves the bot around a "figure-8", two interlocking
   squares. The bot moves forward in the direction it is facing and then
   turns right to begin the far square (counter-clockwise) before finishing
   the close square (clockwise). The size of the squares that make up the
   eight are the same and are specified by the parameter.

   Pre: The desired figure-8 path is not blocked; sizeOfEachEdge is positive
   Post: The bot is in the same position with the same facing as when the
         method was called.
   Parameters: int sizeOfEachEdge - the size (in SimpleBot "blocks")
                 each edge of the figure eight. Must be greater than 0.
   Return Value: void - no return value
   Notes: N/A
*/

Again, note all of the various fields. Only the Notes field is optional. You should include all of the others on every method you write (and you should make sure I include them on every function we write in class). The meaning of the various fields is documented below.

Declaration Comments Whenever you declare a variable or a constant you should have a declaration comment. This comment should indicate where the value for that variable is going to come from (the user with a get* statement, a file, a calculation, etc.). You should also note any limitations on acceptable values for that variable. First an example of what not to do:

// THE FOLLOWING IS WRONG, WRONG, WRONG
int xrayCount; // integer variable for the xray count
// WERE YOU PAYING ATTENTION? THAT WAS WRONG, WRONG, WRONG

Anyone who can read Java code already knows this (and assumes you have chosen a reasonable name for the variable). Much better would be:

int xrayCount;
// dose of x-rays the patient received; entered by the user, should be >= 0

Running Comments Comments that document the code as it is going along are running comments. These comments supliment the code for the human reader. Many example programs in class are rife with running comments, comments that serve as the text for this course.

In general, running comments are only necessary to explain tricky code or introduce different sections of a "large" program or method. What is "tricky" code? If it took you more than a few minutes to figure out the syntax or the format of the code, put a comment on it.

Naming Conventions

Better than a lot of comments explaining what is happening is to have the code document itself. As an example, what does this procedure do?

public double m(double r) {
  final double P = 0.62;
  return r * p;
}

Perhaps the following rendition is clearer:

public double milesFromKilometers(double kilometers)
  final double MILES_PER_KILOMETER = 0.62
  return kilometers * MILES_PER_KILOMETER;
}

Just by choosing good names the function of the code is made clearer. Note the use of a named constant, MILES_PER_KILOMETER; by convention a constant is named using all capital letters (so that it stands out in the code). A named constant is used to make the code easier for a human to read and so that it would be easy to change the value. If 0.62 is not precise enough changing the value of the constant is much easier that looking for every occurrance of "0.62" and figuring out whether or not it needs to be changed

Remember that Java is case sensitive and that it supports more than 60 significant characters in an identifier; this means you should use as complete a name as necessary. You should use internal capitalization or embedded underscores to separate the words inside a multi-word identifier (e.g. initial_velocity or initialVelocity rather than initialvelocity). This may increase the difficulty typing a little bit but the increase in readablilty is worth it.

Classes, variables and constants normally represent things or quantities. They should be named using nouns or noun phrases (e.g. currentVelocity, LUNAR_ESCAPE_VELOCITY, TreasureHuntingBot).

By convention class names begin with a capital letter, variables begin with a lowercase letter, and constants are typed in all capital letters. This makes the general type of a name can be determined simply from the name (e.g. currentVelocity is a variable, LUNAR_ESCAPE_VELOCITY is a constant, and TreasureHuntingBot is a class name).

void methods (also called procedures) normally represent some process or action. They should be named using verbs or verb phrases (e.g. turnLeft(), goToRowColumn(int row, int colum), findBeeper()). Methods are conventionally started with a lowercase letter.

Methods that return a value represent a calculated thing or value. They are best named with a noun, noun phrase, or, occasionally, an adjective indicating how it works (e.g.displacement(), speedFromDisplacement()).

Parameters are just a special kind of variable and should be named and capitalized accordingly.

Indentation and Whitespace

Except inside strings and between the two characters of a two-character token (e.g. between the exclamation point and equal sign in !=), Java is insensitive to spaces, tabs, and carriage returns. Java says you are free to use any layout you like. The goal of structuring your program is to make the logical units of the program obvious to the human reader. Group things that go together together. Separate logical units with blank lines. Indent code within the code it is subordinate to.

Use blank lines judiciously:

Use spaces judiciously:

An example, first of very poor use of whitespace and indentation, and then the same code with a better job should convince the reader that indentation improves readability:

int row, col;
screen.putln("Multiplication Table");
for (row = 1; row <= 12; row++) {
for (col = 1; col <= 12; col++) {
screen.put(row * col, 5);
}
screen.putln();
}

Compare this to:

int row, col;

screen.putln("Multiplication Table");

for (row = 1; row <= 12; row++) {
  for (col = 1; col <= 12; col++) {
    screen.put(row * col, 5);
  }
  screen.putln();
}

The second example uses indentation to show that the second for loop is part of the first loop. The initial putln is not part of the loops at all and is set off by a blank line.

Specific Indentation Patterns

The following examples and descriptions may discuss program structures you have not yet learned; just skip over them.

General Notes: Always place a space between a keyword and a following open parenthesis (if or for). Never place a space between the name of a method and a following open parenthesis. Indentation levels, the amount that subordinate code is indented from the enclosing code, is usually 2, 3, or 4 spaces; the source code in this course will always use 2. Code should be single spaced (though some samples may be double spaced because they were uploaded with the wrong settings).

Long Expressions: If an expression is too long to fit on one line, it should be broken just after an operator so the last thing on the continued line is an operator (makes it clear the expression cannot be complete). Further, continuation lines should be indented so they are "inside" any open parentheses.

displacement = ((acceleration * time * time) +
                (initial_velocity * time) +
                initial_displacement)

if ((lycanthope > 0) && (moon == full) &&
    (silver_bullets == 0)) {
  screen.putln("Run! It's a werewolf!");
}

for(;;) The for loop should start on one line with the declaration of the loop control variable. The three parts of the loop control go on one line or, if necessary, they should be separated at the semicolons. The end of the last line should close the parentheses and open the curly braces for the block of the loop. The closing curly brace should align with the for line while the body is indented one level.

for (x_coordinate = 0; x_coordinate != maxx; ++x_coordinate) {
  g2.draw(new Line2D.Double(0,0,x_coordinate, 100));
}

for (row = 1; row != 6; ++row) {
  for (col = 1; col != 8; ++col) {
    screen.put("*")
  }
  screen.putln();
}

while( ) The beginning of this loop should appear on one line ending with the opening curly brace of the block of the body of the loop unless the boolean condition has to be broken up over multiple lines.

while (user_input != 10) {
  screen.put("enter 10: ");
  user_input = keyboard.getlnInt();
}

while (((x >= 0) && (x <= 12)) ||
       (x % 3 == 0)) {
  screen.putln(x, 5);
  x--;
}

Method Declarations: The method header comment comes directly before the function definition line. The signature line should appear on one line or the parameter list should be broken after a comma. The opening curly brace for the body of the function should appear alone on the next line and the matching closing brace should always have a comment to indicate what it goes with.

void werewolf_check(int moon, int silver_bullets)
{
  if ((moon == full)  &&
      (silver_bullets <= 0)) {
    screen.putln("Run!");
  }
} // werewolf_check