Contents:
Coding style is an important part of good software engineering practice. The goal is to write code that is clear and easy to understand, reducing the effort required to make future extensions or modifications.
In 6.170 we do not specify a detailed coding style that you must follow. However we expect your code to be clear and easy to understand. This handout provides overall guidelines within which you should develop your own effective coding style.
Many other style guides are available. For example, you can see Sun's Code Conventions for the Java Programming Language. We do not require you to follow those guidelines — they are just one way to write your code in a comprehensible fashion, but you might consider them while developing your own style.
Names for packages, types, variables, and branch labels should document their meaning and/or use. This does not mean that names need to be very long. For example, names like i and j are fine for indexes in short loops, since programmers understand the meanings and uses of these variables by convention.
You should follow the standard Java convention of capitalizing names of classes, but starting method, field, variable, and package names with a lower case letter. Constants are named using all uppercase letters. The Java Language Specification provides some common Naming Conventions that you may want to use when naming your classes, methods, etc.
Indenting code consistently makes it easy to see where if statements and while loops end, etc. You should choose consistent strategies; for example, be consistent about whether you put the open curly brace on the same line as the if or on the next line, or what your try-catch-finally blocks look like. Examine the code in the textbook for a sample style; feel free to develop your own if it makes you more comfortable.
In Emacs's Java mode, return indents the next line to (its guess at) the correct column, and the tab key re-indents the current line. There are also commands for re-indenting an entire region of lines.
In Eclipse Ctrl-F will correctly indent your code.
Consistent (and adequate) spacing also helps the reader. There is no reason to try to jam your code into as few columns as possible. You should leave a space after the comma that separates method arguments. You should leave a space between for, if, or while and the following open parenthesis; otherwise, the statement looks too much like a method call, which is confusing. In general, you should place only one statement on each line.
Don't make the mistake of writing comments everywhere — a bad or useless comment is worse than no comment. If information is obvious from the code, adding a comment merely creates extra work for the reader. For example, this is a useless comment:
i++; // increment
Good comments add information to the code in a concise and clear way. For example, comments are informative if they:
// Compute the standard deviation of list elements that are
// less than the cutoff value.
for (int i=0; i<n; i++) {
// ...
}
An important application of this type of comment is to document the arguments and return values of functions so clients need not read the implementation to understand how to use the function.
// Signal that a new transfer request is complete and ready
// to process. The manager thread will begin the disk transfer
// the next time it wakes up and notices that this variable has changed.
buffer_manager.active_requests ++;
// The buffer contains at least one character.
// (If the buffer is empty, the interrupt handler returns without
// invoking this function.)
c = buffer.get_next_character();
if (n > 0) {
average = sum / n;
} else {
// XXX Need to use decayed average from previous iteration.
// For now, just use an arbitrary value.
average = 15;
}
Hints:
In Java, /* and */ can be used to block off large chunks of code whereas // is used to comment out everything from a // to the end of a line. In practice, /* and */ should be reserved for Javadoc comments (see the next section), in which case the opening tag should have an additional asterisk: /**. If you need to highlight a large block of code, then highlight the region and use Ctrl+/ in Eclipse. This is better because block comments do not nest. For example, if you already did:
String a = "Athena "; String b = "bites"; /* String b = "brings me happiness"; */ String c = "closes? Nope. Never."; String d = "doesn't have anywhere to sleep comfortably.";
But then you wanted to comment out the creation of variables b and c using a block comment, you would have:
String a = "Athena "; /* String b = "bites"; /* String b = "brings me happiness"; */ String c = "closes? Nope. Never."; */ String d = "doesn't have anywhere to sleep comfortably.";
(The two block comment characters that have been added are in red and the code that is commented out by the new block comment is underlined.) Notice that this failed to comment out the statement where c is created. Also, this code will no longer compile because there is a */ dangling by itself after the definition of c. This may seem easy to fix now, but if you have commented a large block of code, it may be a pain to find the nested block comment that is causing the compilation error. You can avoid this mess entirely by using the // comment:
String a = "Athena "; // String b = "bites"; // // String b = "brings me happiness"; // String c = "closes? Nope. Never."; String d = "doesn't have anywhere to sleep comfortably.";
This also makes it easier to uncomment smaller blocks of commented regions. Use Ctrl+\ to uncomment code in Eclipse.
If you want to leave yourself a note about a piece of code that you need to fix, preface the comment with TODO. You will notice that TODO will appear in bold and that if you do Window > Show View > Tasks, then a a “Tasks” pane will come up with all of the things you have left yourself TODO. You can jump to these points in your code quickly by double-clicking on them in the “Tasks” pane.
At a minimum, every class or interface that you write, along with every nontrivial public method you create, should have a Javadoc comment. Good documentation is complete without being excessive, so try to be succinct, but unambiguous, when documenting your code.
HelloWorld has a several Javadoc comments: at the top of the file, before the class declaration, before the greeting field, and before each method. You can tell that these are Javadoc comments because of where they appear in the code and because they start with /** instead of /*.
It is important to use this syntax to document your code so that your comments will appear in the HTML documentation generated by the Javadoc tool (this is how the documentation for Sun's API is generated, as well). There are a number of Javadoc Tags that get formatted in a special way when the HTML documentation is generated. You can identify these tags because they start with the @ sign, such as @param and @return.
For 6.170, we use a few additional Javadoc tags that are not recognized by Sun's Javadoc tool: @requires, @modifies, and @effects. See “Using javadoc to generate specs” for more information.
When someone else (such as your TA) is trying to understand your Java code, he or she will often first look at the generated Javadoc to figure out what it does. Thus, it is important that you check the generated HTML yourself to ensure that it clearly and accurately communicates the contracts of your code.
As a general rule, you should never have type casts in code you write for 6.170. They are a work-around which hides information from the type system and prevents the compiler from flagging real bugs in your code.
However, there are some over-broad legacy interfaces in the Java library which require the use of casts. These were, in general, written in Java's dim past before it had the powerful type system it has today — some of these interfaces are quite widely used, however. Implementing these “over-broad” interfaces is the only time type casts should appear in your code.
The following is a fairly complete list of interfaces in the Java API which require casts. Unless you are implementing one of these, there should be no type casts in your code:
All implementations of: Some (not all) implementations of:These may require unchecked casts (even worse!):
- Object.clone()
- Collection.contains() (and subclasses of Collection, like List and Set)
- Collection.remove() (and subclasses)
- Map.containsKey()
- Map.containsValue()
- Map.get()
- Map.remove()