Project IT has committed to establishing and enforcing programming standards for the Java language. This document presents the Java language coding standards recommended for adoption by Development Group. Observing programming standards is important for the following reasons:
· Code written to standard is easier to read and maintain. Most code is not maintained for its entire lifetime by the original author.
· Maintenance accounts for 80% of the lifetime cost of software. The easier code is to maintain, the lower its ultimate cost.
· Programmer productivity increases over the long term, because programmers become coding to standard becomes second nature, and less efficient coding methods are abandoned, and because of the savings in maintenance time.
Coding standards are important because they lead to greater consistency within your code and the code of your teammates. Greater consistency leads your code that is easier to understand, which in turn means it is easier to develop and to maintain.
Development guidelines provide two high-level benefits: they reinforce techniques to design and code better and they provide consistency even when there is no clear best choice. This document provides guideline recommendations that focus on the first of these benefits: all of the guidelines in here are meant to help build better software.
Standards only work if everyone observes them. Some of the standards in this document deal with fine details, such as white space and other spacing issues. We recognize that pretty print is less important than content, but make the point that it is important that we make shared code readable by a large audience, and to that end, people should conform to the standards as much as possible.
1.1 Purpose
The purpose of this document is to describe the Java programming standards adopted by Project IT Development Group.
1.2 When and How to Apply the Standard
· All new code in Development Group must conform to the standard
· You do not need to go through existing code gratuitously to make it conform to the standard
· Anytime any significant change is made to a piece of code then changes can be made to make the whole file conform to the standard.
· Configure the IDE you use, for brace style, spacing and javadoc etc. to make it conform to the standard.
2.1 Packages
Create a new Java package for each functional component. Create and use directories as recommended by Java’s package conventions. Packages provide a means of grouping classes of related function or purpose, and create the logic of the file organization. Classes grouped in packages can share access to methods and variables, while hiding the complexity of their interaction from other objects that don't use that information.
See 4.2.1 for package naming conventions.
2.2 Files
Each Java class should be placed in a separate file. A file consists of sections separated by blank lines. Optionally, a comment can identify each section.
Files longer than 1000 lines are cumbersome and should be avoided.
2.2.1 File Structure
Java source files should be structured as follows:
· Package and import statements.
· Class and interface declarations.
2.2.1.1 Package and Import Statements
The first non-comment line should be the package statement, followed by import statements.
Example
package com.mortgagefamily.yyy.acl;
import java.util.Vector;
import java.util.Hashtable;
2.2.1.2 Class and Interface Declarations
Class and interface declarations should appear in the Java source file in the following order:
· Class/interface Javadoc comment (/**...*/) with author, version and copyright information in addion to a class description. See section 3.1.1 for details on javadoc comments.
· Class or interface statement.
· Class/interface implementation comment (/**...*/), if necessary. This comment should contain any class-wide or interface-wide information that wasn't appropriate for the class/interface documentation comment.
· Class (static) variables. The public class variables appear first, then protected, then package level (no access modifier), and then private.
· Instance variables. First public, then protected, then package level (no access modifier), and then private.
· Constructors.
· Methods. Methods should be grouped by functionality rather than by scope or accessibility. For example, a private class method can be between two public instance methods. The goal is to make reading and understanding the code easier.
Making code understandable is especially important in an object-oriented programming environment, because the point is to create reusable objects. Writing logical, clear, concise documentation in the source code itself promotes both well constructed applications and easier maintenance. Creating good source code documentation is time consuming, but well worth the effort over the life of the product.
3.1 Comments
3.1.1 Documentation Comments
A really good rule of thumb to follow regarding documentation is to ask yourself if you’ve never seen the code before, what information would you need to effectively understand the code in a reasonable amount of time.
General Concepts:
· Comments should add to the clarity of your code
· If your program isn’t worth documenting, it probably isn’t worth running
· Avoid decoration, i.e. do not use banner-like comments
· Keep comments simple
· Write the documentation before you write the code
· Document why something is being done, not just what
Use documentation comments immediately before declarations of interfaces, classes, member functions, and fields to document them. Documentation comments are processed by javadoc, to create external documentation for a class. For detailed specifications on Javadoc commenting requirements.
Naming conventions make programs more understandable by making them easier to read. They also provide information about the function of the identifier, such as whether the identifier is a constant, package, or class, which can be helpful in understanding the code.
4.1 General Naming Conventions
Observe the following general naming conventions.
· Use full English descriptors that accurately describe the variable, field, or class. For example, use names like firstName, grandTotal, or corporateCustomer. Although names like x1, y1, or fn are easy to type because they are short, they do not provide any indication of what they represent, and result in code that is difficult to understand, maintain, and enhance.
· Use terminology applicable to the domain. If users refer to their clients as customers, then use the term Customer for the class, not Client. Many developers make the mistake of creating generic terms for concepts when perfectly good terms already exist in the industry/domain.
· For readability, follow these case conventions. For class and interface names, use UpperCamelCase. For methods, variables, and so on, use lowerCamelCase.
· Use abbreviations sparingly and intelligently. Maintain a list of standard short forms (abbreviations). Choose them wisely, and use them consistently. For example, to abbreviate the word "number," choose one of nbr, no, or num, document it, and use it consistently.
· Avoid long names without jeopardizing readability. Less than 20 characters is an appropriate guideline.
· Avoid names that are similar or that differ only in case. For example, the variable names persistentObject and persistentObjects should not be used together. Nor should anSqlDatabase and anSQLDatabase.
· Do not hide names. Name hiding refers to the practice of giving a local variable, argument, or field the same (or similar) name as that of another one of greater scope. For example, if you have a field called firstName do not create a local variable or parameter called firstName, or anything close to it like firstNames or fistName. This makes your code difficult to understand and prone to bugs because other developers, or you, will misread your code while they are modifying it and make difficult to detect errors.
· Avoid leading or trailing underscores. Names with leading or trailing underscores are usually reserved for system purposes, and should not be used for any user-created names except for pre-processor defines.
· If the name of the field begins with an acronym, such as sqlDatabase, then the acronym (in this case ‘sql’) should be completely in lowercase. Do not use sQLDatabase for the name.
· In case of EJB, remote interface name should be the EJB Bean name, home interface should be EJB Bean name with “Home” suffixed and Bean class name should be EJB Bean name with “Bean” suffixed.
4.2 Specific Naming Conventions
This section provides standards for naming specific objects.
4.2.1 Package Names
Packages names shall begin with either the firm’s domain name or with one of the English two-letter codes that identify countries, and should be cast in ASCII alphabetic characters. Current domain suffixes include: com, edu, gov, mil, net, and org.
Example
../com/mortgagefamily/yyy/acl/..
4.2.2 Class Names
Class names should be nouns, cast in UpperCamelCase. Keep class names simple and descriptive. Avoid acronyms and abbreviations (unless the abbreviation is more widely used than the long form, such as URL or HTML).
Example
Customer
FinancialInstrument
4.2.3 Interface Names
Interface names are external facing. Interface names should follow the rules for class names. In addition, you can add an optional suffix, such as able, ible, or er, to interface names to indicate the interface function.
Example
Runnable
Contactable
Prompter
Singleton
4.2.4 Exception Classes
Exception classes follow the naming conventions for classes. Append the word Exception to the end of all exception classes.
Example
RemoteException
NamingException
4.2.5 Method Names
Methods should be verbs cast in lowerCamelCase.
Accessor methods should be prefixed with get or set, as appropriate.
Example
run()
getBackground()
getFirstName()
setFirstName()
isChecked()
4.2.6 Compilation Unit Files
Use the name of the class or interface for the name of the compilation unit and add the extension .java. If there is more than one class or interface, use the name of the primary class.
Customer.java
FinancialInstrument.java
4.2.7 Fields, Attributes, Properties
Field, attribute, property names should be cast as a full English description of the field in lowerCamelCase. Using prefixes and/or hungarian notation is not recommended as these mechanisms are sensitive to data type changes and changing the data type of an attribute changes the name of the accessors, mutators and impacts users. The names of accessors and mutators also become unwieldy with attribute names with prefixes and/or the hungarian notation.
firstName
settleDate
datedDate
4.2.8 Local Variables
Local variables should be cast as a full English description in lowerCamelCase. Take care not to hide existing fields. For example, if there is a field named firstName, do not name a variable firstName. Using prefixes and/or hungarian notation is not recommended to maintain consistency and reduce the number of changes that have to be made to the code if the data type of a variable changes.
issueDate
maturity
yieldToMaturity
4.2.9 Loop Counters
If loops are short it is generally accepted to use the letters i, j, k for the loop counter. If the loop counter has some specific business connotation then use a descriptive name such as customerIndex etc. for the loop counter.
If a loop block becomes long over time then using single character counter names can introduce errors during refactoring, as they are hard to find. Generally loops should be kept short and a long loop usually indicates the need for delegation of some of the functionality in the loop to other methods.
Example
i
j
k
counter
customerIndex
4.2.10 Constants
The names of variables and declared class constants should be all uppercase letters, with words separated by underscores. ANSI constants should be avoided, for ease of debugging.
Example
static final int MIN_WIDTH = 4;
static final int MAX_WIDTH = 999;
Tasteful spacing makes Java code more readable. Conventions regarding spacing are presented in this section.
5.1 White Space
Adding white space to Java code helps make it readable by breaking it up into small, easy-to-digest sections. Without white space, code can be difficult to read and understand.
5.1.1 Blank Lines
Use blank lines as follows:
· Use a single blank line to separate logical groups of code, such as control structures.
· Use two blank lines to separate member function documentation.
5.1.2 Inline Spaces
Observe the following standards for using inline spaces.
· Use a single space to separate a keyword followed by a parenthesis:
while (true) {
· Do not use a space between a method name and its opening parenthesis.
· A space should follow each comma in parameter lists.
· The expressions in a for statement should be separated by blank spaces.
for (expr1; expr2; expr3)
· Casts should be followed by a blank space.
myMethod((byte) aNum, (Object) x);
myMethod((int) (cp+5), ((int) (x + 3)) +1);
· Use one space in between the type and identifier in variable declarations.
int level;
int size;
Customer myCustomer;
5.2 Line Spacing and Width
Line width should not normally exceed 80 characters. Indentation size should be set to 4 spaces . Use of tabs for indentation is discourgaed as it causes the code to align differently under different tab settings. If tabs are used they should be set to expand to 4 spaces.
5.3 Braces
Always use braces even if a compound statement has only one line. Illustrated below are three possible recommendations on a brace strategy to be adopted by projects. Pick one and conform to it on your particular project. All example code in this document adheres to strategy 3.
Brace Strategy 1:
class Sample extends Object {
int Method(){
for (int i=0; i<10; i++) {
try {
// do something
} catch (SomeException e) {
// corrective action
} finally {
// cleanup
}
}
}
}
Brace Strategy 2:
class Sample extends Object
{
int Method()
{
for (int i=0; i<10; i++)
{
try
{
//do something
}
catch (SomeException e)
{
// corrective action
}
finally
{
// cleanup
}
}
}
}
Brace Strategy 3:
class Sample extends Object
{
int Method()
{
for (int i=0; i<10; i++) {
try {
//do something
} catch (SomeException e) {
// corrective action
} finally {
// cleanup
}
}
}
}
5.4 Wrapping Lines
When an expression will not fit on a single line, break it according to these general principles:
· Break after a comma.
· Break before an operator.
· Prefer higher-level breaks to lower-level breaks.
· Align the new line with the beginning of the expression at the same level on the previous line.
Here are some examples of breaking method calls:
someMethod(longExpression1, longExpression2, longExpression3,
longExpression4, longExpression5);
var = someMethod1(longExpression1,
someMethod2(longExpression2, longExpression3));
Observe the following standards regarding declarations.
6.1 Number Per Line
Follow these standards regarding number of declarations per line.
· One declaration per line is recommended to encourage commenting.
· Do not put different types on the same line.
Preferred:
int level; // indentation level
int size; // size of table
Avoid:
int level, size;
int foo, fooarray[]; //WRONG!
6.2 Initialization
· Initialize local variables where they are declared. The only reason not to initialize a variable where it's declared is if the initial value depends on some computation occurring first.
· Declare a local variable only at that point in the code where you know what its initial value should be. This practice minimizes bad assumptions about the values of variables.
· Declare and initialize a new local variable rather than reusing (reassigning) an existing one whose value happens to no longer be used at that program point. This practice minimizes bad assumptions about the values of variables.
6.3 Placement
· Avoid local declarations that hide declarations at higher levels. For example, do not declare the same variable name in an inner block.
Example
int count;
...
myMethod()
{
if (condition) {
int count = 0; // AVOID!
}
}
· Within loops, objects should be re-used rather than re-created for performance reasons.
6.4 Method Declarations
For method declarations, follow these format rules.
· Methods without arguments should be defined on a single line.
· All method qualifiers (scope, static, abstract, final, native, synchronized, return type) should appear on the same line as the method name.
· Methods should be kept small.
· Arguments should follow the method declaration on the same line. If the maximum width is reached and there are more arguments, place subsequent arguments on a new line indented one tab from the method declaration. This is the format created by most code generators. It is also acceptable to place each argument on a new line, indented one tab from the method declaration.
· For methods that throw exceptions, the throws keyword and exception type should appear on a new line following the argument close parenthesis. The throws keyword should be indented one tab from the method declaration.
· A blank line should be placed between method declarations.
Example
public Boolean VerifyAccount(String id, String firstName,
String lastName, double balance)
throws NegativeBalanceException
{
…
}
Observe the specified format for following constructs.
7.1 If Else Constructs
Place the if keyword and conditional expression on the same line.The statement is on the next line.
Example
if (expression) {
statement;
} else {
statement;
}
7.2 While Constructs
The while construct has the same format as the if construct. The while keyword should appear on its own line, immediately followed by the conditional expression. The statement block should appear on the next line.
Example
while (expression) {
statement;
}
7.3 Do While Constructs
The DO..WHILE form of the while construct should appear as shown below:
Examples
do {
statement;
} while (expression);
7.4 Switch Construct
The switch construct uses the same layout format as the if construct. The switch keyword should appear on its own line, immediately followed by its test expression. The statement block is placed on the next line.
Example
switch (expression) {
case n:
statement;
break;
case x:
statement;
break;
default: //always add the default case
statement;
break;
}
7.5 Try / Catch Construct
The try/catch construct is similar to the others. The try keyword should appear on its own line; followed by the statement body.
Any number of catch statements are next, consisting of the catch keyword and the exception expression on its own line; followed by the catch body. The finally clause is the same as a catch .
Example
try {
statement;
} catch (ExceptionClass e) {
statement;
} finally {
statement;
}
· Use exceptions to handle logic and programming errors, configuration errors, corrupted data, resource exhaustion. Report exceptions by the appropriate logging mechanism as early as possible, including at the point of raise.
· Minimize the number of exceptions exported from a given abstraction.
In large systems, having to handle a large number of exceptions at each level makes the code difficult to read and to maintain. Sometimes the exception processing dwarfs the normal processing.
There are several ways to minimize the number of exceptions:
· Export only a few exceptions but provide "diagnosis" primitives that allow querying the faulty abstraction or the bad object for more detailed information about the nature of the problem that occurred.
· Add "exceptional" states to the objects, and provide primitives to check explicitly the validity of the objects.
8.1 Exception Handling
All significant blocks of code begin with a try clause and end with a catch clause. Remember that there is a performance hit with inserting try catch clauses therefore refrain from adding try catch clauses in accessors and mutators.
8.2 Error and Exception Notification
There should be no return codes from methods that have default values like –1, 99 signifying error/failure conditions.
All errors are reported as exceptions. There are two kinds of exceptions.
· System Exceptions
· Application Exceptions.
System exceptions are things like, Out of Memory, Database Deadlock, Optimistic Lock etc. Application exceptions a communication mechanism for application errors and user messages like the “Trade details invalid”, “Settlement Date must be on or after Trade Date”, “Invalid CUSIP” etc.
Every Application should declare one sub-type exception. e.g. FrameworksException, BookNewException etc. This ApplicationException inherits from java.lang.Exception and contains within it an ErrorMessage object containing the actual error code, a cryptic error (“technical”) description and friendly error message.
The application code just knows about the appropriate error code that needs to be communicated to the user from that location. When an exception condition happens it creates an appropriate error message object from the error code and throws an Application Exception with the Error Message object included. So that the clients can catch the exception extract the friendly error message and report it to the end user or log it to a file.
9.1 Don't optimize as you go
Write your program without regard to possible optimizations, concentrating instead on making sure that the code is clean, correct, and understandable. If it's too big or too slow when you've finished, then you can consider optimizing it.
9.2 Remember the 80/20 rule
In many fields you can get 80% of the result with 20% of the effort (also called the 90/10 rule - it depends on who you talk to). Whenever you're about to optimize code, use profiling to find out where that 80% of execution time is going, so you know where to concentrate your effort.
Always run "before" and "after" benchmarks:
How else will you know that your optimizations actually made a difference? If your optimized code turns out to be only slightly faster or smaller than the original version, undo your changes and go back to the original, clear code.
9.3 Use the right algorithms and data structures
Don't use an bubblesort algorithm to sort a thousand elements when there's quicksort available. Similarly, don't store a thousand items in an array that requires a search when you could use hash table.
9.4 Document optimizations
Highly optimized code may be hard to read and maintain. Having documentation helps with maintenance.
In this section we will cover several techniques that help to separate the professional developers from the hack coders. These techniques are:
· Document your code
· Paragraph your code
· Follow the thirty-second rule
10.1 Document Your Code
Remember, if your code isn’t worth documenting then it isn’t worth keeping (Nagler, 1995). When you apply the documentation standards and guidelines proposed in this paper appropriately you can greatly enhance the quality of your code.
10.2 Paragraph/Indent Your Code
One way to improve the readability of a member function is to paragraph it, or in other words indent your code within the scope of a code block. Any code within braces, the { and } characters, forms a block. The basic idea is that the code within a block should be uniformly indented one unit.
10.3 Follow the Thirty-Second Rule
Another programmer should be able to look at your member function and be able to understand what it does, why it does it, and how it does it in less than 30 seconds. If he or she can’t then your code is too difficult to maintain and should be improved. Thirty seconds, that’s it. A good rule of thumb is that if a member function is more than a screen then it is probably too long.
The standards presented are in line with Sun’s Java conventions, and should be relatively easy to conform to. Following these standards will create more consistent code that is easier for colleagues to understand and maintain. Going against the standard is not recommended but, if your project makes a conscious decision for a valid reason to go against one of the standards then this should be clearly documented.
The following sources were used to compile the standards presented in this document.
1. Sun Microsystems. Code Conventions for the Java Programming Language.
2. Netscape Java Coding Standards.
3. Ambler, Scott. Java Coding Standards.
4. Jonathan Hardwick’s home page.