Google
WEB
http://www.dugaldmorrow.com
Java Coding Guidelines - Part C PDF Print E-mail

 

6.2      Types

 

Convert types explicitly to highlight the conversion and therefore the possible loss of precision or raising of NullPointerException, etc. For example, replace:

 

float width = bounds.getWidth();

int roadId = road.getId();

 

with:

 

float width = (float) bounds.getWidth();

int roadId = (int) road.getId();

 

 

6.3      Exiting Blocks

 

Minimize the number of break statements in loops.

 

Minimize the number of return statements in methods.

 

Move any loop-independent code out of the loop. Although "code hoisting" is a common compiler optimization, it cannot be done when the invariant code makes calls to other compilation units. In the following example, getConnection() is loop independent but the compiler probably won’t hoist it since the call may have (intended) side effects:

 

for (int imageIndex = 0; imageIndex < numberOfImages; imageIndex++) {

   Connection connection = getConnection();

   images[imageIndex] = construct(imageFileNames[imageIndex], connection);

}

 

 

Use a case statement rather than a series of "else if" statements when the branching condition is a discrete value.

 

Methods should generally have a single point of return. Return statements sprinkled freely over a method are akin to goto statements, making the code difficult to read and to maintain.

 

Void methods should have no return statements at all.

 

Multiple returns can be tolerated only in very small methods, when all returns can be seen simultaneously and when the code has a very regular structure:

 

SomeClass getSomeAttribute() {

   if (someCondition) {

          return thisValue;

   } else {

          return thatValue;

   }

}

 

Street findStreet(final String name) {

   for (Street street: streets) {

          String streetName = street.getName();

          if (streetName.equals(name)) {

                 return street;

          }

   }

   return null;

}

 

 

6.4      Code Clarity

 

Introduce intermediate variables to clarify code and aid debugging. For example, replace:

 

if (file.exists() && file.canWrite() && fileName.indexOf(pattern) >= 0) {

   doSomething();

}

 

with:

 

boolean fileWritableAndMatchesPattern =

   file.exists() &&

   file.canWrite() &&

   fileName.indexOf(pattern) >= 0;

if (fileWritableAndMatchesPattern) {

   doSomething();

}

 

Reduce cascading of method calls since the resulting code is less readable, reduces re-use of local variables, is more difficult to debug and often results in NullPointerExceptions. For example, replace:

 

 

renderIcon(

   mapPlugin.getResource(“Marker.png”),

   Map.getCurrent().getSelection().getLatitude(),

   Map.getCurrent().getSelection().getLongitude());

 

with:

 

File markerIconFile = mapPlugin.getResource(“Marker.png”);

Map currentMap = Map.getCurrent();

Selection selection = currentMap.getSelection();

Double latitude = selection.getLatitude();

Double longitude = selection.getLongitude();

renderIcon(markerIconFile, latitude, longitude);

 

 

7         Code Design

 

Write methods that only do "one thing". Methods should generally be categorized as either functions or procedures – not both. Violations of this guideline are justified in utility type operations or to support efficiency and concurrency.

 

It is preferable to specify abstract methods rather than relying on overriding no-op concrete methods.

 

Always override Object.hashCode() when overriding Object.equals(Object).

 

8         Security

 

Limit the visibility of classes, interfaces, methods and fields. Refrain from increasing the accessibility of an inherited method, as doing so may break assumptions made by the superclass.

 

Limit the extensibility of classes and methods. Either design classes and methods for inheritance and overriding or otherwise make them final.

 

9         Concurrency

 

Name threads so that they can be identified using debuggers, JConsole, etc.

 

When spawning a thread, use an exception handler in the entry method of the child thread to avoid or at least report the unexplained death of the child thread.

 

In subsequent rules, a distinction is made between service threads and application threads. Service threads are small and algorithmically simple tasks that are used to provide the "glue" between application-related tasks. Examples of service threads (or intermediary threads) include buffers, transporters, relays, agents, monitors, and so on that usually provide synchronization, decoupling, buffering, and waiting services. Application threads, as the name conveys, are more directly related to the primary functions of the application.

 

Avoid hybrid threads: application threads should be made pure callers; service threads should be made pure callees.

 

Avoid circularities in the graph of entry calls.  This will considerably reduce the risk of deadlocks.

 

Minimise the use of shared objects that require locking to minimise friction.

 

Restrict the use of sleep statements. Arbitrary suspension of a thread may lead to severe scheduling problems, which are hard to track down and correct.

 

Minimise the use of thread priorities since this suggests a design that is over sensitive to the environment in which the application is executed.

 

Use the Timer and TimeTask classes in package java.util for task scheduling.

 

Avoid busy wait (polling) so as not to monopolise the CPU. For example, use LinkedBlockingQueue.take() in preference to LinkedBlockingQueue.poll().

 

Do not rely on any specific activation order for threads since they are asynchronous.

10   Error Handling and Exceptions

 

The general philosophy is to use exceptions for erroneous conditions that can not be handled at the point where the error occurs. Note that erroneous conditions are to be expected, even during the course of normal operation.

 

Checked exceptions are preferred over runtime exceptions. Runtime exceptions should only be used to prevent code being cluttered with exception declarations and handlers. In general, exceptions that indicate an improper use of a class should be either unchecked (runtime exceptions) or assertion errors.

 

Report exceptions by the appropriate logging mechanism as soon as it is evident that the condition should not occur during the normal course of operation. This will often be at the point where the exception occurred.

 

Minimize the number of types of exceptions declared by a given abstraction.

 

One way to reduce the use of exceptions is to introduce "exceptional" states to the objects, and provide routines to check explicitly the validity of the objects.

 

Do not propagate exceptions not specified in the design.

 

Trap Throwable only at the bottom of a thread or where it is re-raised.

 

while (processingEnabled) {

   try {

          doSomething();

   } catch (Throwable t) {

          logger.error(“An unexpected ” + t.getClass() + “ exception occurred.”, t);

   }

}

 

 

Avoid nesting exceptions within the same method.

 

Do not use exceptions for frequent, anticipated events. There are several inconveniences in using exceptions to represent conditions that are not clearly errors:

 

  • It is confusing;
  • It usually forces some disruption in the flow of control that is more difficult to understand and to maintain;
  • It makes the code more painful to debug.

 

Do not use exceptions for returning non erroneous results of an operation. E.g Do not create an exception such as ObjectNotFoundInSearchError. Use a return type that can convey the entire result (a search result would contain attributes and corresponding accessor methods to determine if the value was found and the location of the value).

 

Do not use exceptions to implement control structures. This is a special case of the previous rule: exceptions should not be used as a form of "goto" statement.

 

11   Portability

 

Code should be written in a portable manner. Any code that can not, should be co-located and should implement some type of platform abstraction such as:

 

public interface Platform {

 

   String getApplicationPreferencesDirectorPath(String ApplicationName);

 

}

 

 

Path names should use the same case of the actual paths since some operating system path names are case sensitive.

 

Use system properties for platform specific values. E.g:

 

public static final String LINE_SEPARATOR = System.getProperty(“line.separator”);

 

 

Forward slashes can be used in paths since it is the accepted standard on many operating systems (Windows handles both forward and backward slashes) and can simply code.

 

 

<< Back

 
< Prev   Next >