java development company
Java

What are the Best Practices in Coding Java [Developer’s Guide]

In this blog, we will discuss in detail about the best practices to follow while coding Java based applications.

The pitfall of a large application is maintaining a huge code base with hundreds of dependencies – such a monolith slows down developers as they try to incorporate new features.

Instead, partition your code into components, each gets its own folder or a dedicated codebase, and ensure that each unit is kept small and simple.  

The ultimate solution is to develop small software: divide the whole stack into self-contained components that don’t share files with others, each constitutes very few files (e.g. API, service, data access, test, etc.) so that it’s very easy to reason about it.

So promoting a uniform directory structure across projects is also one of its important aspects.

Here we’ll be following standard directory layout of a typical Maven project.

1. Directory Layout

A typical Maven project has a pom.xml file and a directory structure based on defined conventions:

└───maven-project
  ├───pom.xml
      ├───README.txt
     ├───NOTICE.txt
  ├───LICENSE.txt
      └───src
             ├───main
        │   ├───java
        │   ├───resources
        │   ├───filters
        │   └───webapp
        ├───test
        │   ├───java
        │   ├───resources
        │   └───filters
        ├───it
        ├───site
        └───assembly

The default directory layout can be overridden using project descriptors, but this is uncommon and discouraged.

1.1 The Root Directory

This directory serves as the root of every Maven project.

Following are the standard files and subdirectories that are typically found at root:

  • maven-project/pom.xml – defines dependencies and modules needed during the build lifecycle of a Maven project
  • maven-project/LICENSE.txt – licensing information of the project
  • maven-project/README.txt – summary of the project
  • maven-project/NOTICE.txt – information about third-party libraries used in the project
  • maven-project/src/main – contains source code and resources that become part of the artifact
  • maven-project/src/test – holds all the test code and resources
  • maven-project/src/it – usually reserved for integration tests used by the Maven Failsafe Plugin
  • maven-project/src/site – site documentation created using the Maven Site Plugin
  • maven-project/src/assembly – assembly configuration for packaging binaries

1.2 The src/main Directory

src/main is the most important directory of a Maven project. Anything that is supposed to be part of an artifact, be it a jar or war, should be present here.

Its subdirectories are:

  • src/main/java – Java source code for the artifact
  • src/main/resources – configuration files and others such as i18n files, per-environment configuration files, and XML configurations
  • src/main/webapp – for web applications, contains resources like JavaScript, CSS, HTML files, view templates, and images
  • src/main/filters – contains files that inject values into configuration properties in the resources folder during the build phase

1.3 The src/test Directory

The directory src/test is the place where tests of each component in the application reside.

Hire Full Stack Java Developers from Perfomatix

Note that none of these directories or files will become part of the artifact. Let’s see its subdirectories:

  • src/test/java – Java source code for tests
  • src/test/resources – configuration files and others used by tests
  • src/test/filters – contains files that inject values into configuration properties in the resources folder during the test phase

2. Error Handling Practices

2.1 Clean Up Resources in a Finally Block or Use a Try-With-Resource Statement

It happens quite often that you use a resource in your try block, like an InputStream, which you need to close afterwards. A common mistake in these situations is to close the resource at the end of the try block.

public void doNotCloseResourceInTry() {

                                    FileInputStream inputStream = null;

                                     try {

                                            File file = new File("./tmp.txt");

                                            inputStream = new FileInputStream(file);

                                            // use the inputStream to read a file

                                            // do NOT do this

                                             inputStream.close();

                                          } catch (FileNotFoundException e) {

                                                         log.error(e);

                                          } catch (IOException e) {

                                                          log.error(e);

                                          }

                                   }

The problem is that this approach seems to work perfectly fine as long as no exception gets thrown. All statements within the try block will get executed, and the resource gets closed.

But you added the try block for a reason.

You call one or more methods which might throw an exception, or maybe you throw the exception yourself. That means you might not reach the end of the try block. And as a result, you will not close the resources.

You should, therefore, put all your clean up code into the finally block or use a try-with-resource statement.

2.2  Use a Finally Block

In contrast to the last few lines of your try block, the finally block gets always executed.

That happens either after the successful execution of the try block or after you handled an exception in a catch block. Due to this, you can be sure that you clean up all the opened resources.

public void closeResourceInFinally() {

FileInputStream inputStream = null;

   try {

      File file = new File("./tmp.txt");

        inputStream = new FileInputStream(file);

    // use the inputStream to read a file

} catch (FileNotFoundException e) {

        log.error(e);

    } finally {

        if (inputStream != null) {

            try {

                inputStream.close();

            } catch (IOException e) {

                log.error(e);

           }

       }

   }

}

2.3 Prefer Specific Exceptions

The more specific the exception is that you throw, the better. Always keep in mind that a coworker who doesn’t know your code, or maybe you in a few months, need to call your method and handle the exception.

Therefore make sure to provide them as much information as possible. That makes your API easier to understand. And as a result, the caller of your method will be able to handle the exception better or avoid it with an additional check.

So, always try to find the class that fits best to your exceptional event, e.g. throw a NumberFormatException instead of an IllegalArgumentException. And avoid throwing an unspecific Exception.

public void doNotDoThis() throws Exception {

   ...

}

public void doThis() throws NumberFormatException {

   ...

}

2.4 Document the Exceptions You Specify

Whenever you specify an exception in your method signature, you should also document it in your Javadoc.

That has the same goal as the previous Java best practice: Provide the caller as much information as possible so that he can avoid or handle the exception.

So, make sure to add a @throws declaration to your Javadoc and to describe the situations that can cause the exception.

/**

* This method does something extremely useful ...

*

* @param input

* @throws MyBusinessException if ... happens

*/

public void doSomething(String input) throws MyBusinessException {

   ...

}

2.5 Throw Exceptions With Descriptive Messages

The idea behind this best practice is similar to the two previous ones. But this time, you don’t provide the information to the caller of your method.

The exception’s message gets read by everyone who has to understand what had happened when the exception was reported in the log file or your monitoring tool.

It should, therefore, describe the problem as precisely as possible and provide the most relevant information to understand the exceptional event.

Don’t get me wrong; you shouldn’t write a paragraph of text. But you should explain the reason for the exception in 1-2 short sentences.

That helps your operations team to understand the severity of the problem, and it also makes it easier for you to analyze any service incidents.

If you throw a specific exception, it’s class name will most likely already describe the kind of error. So, you don’t need to provide a lot of additional information.

A good example of that is the NumberFormatException. It gets thrown by the constructor of the class java.lang.Long when you provide a String in the wrong format.

try {
   new Long("xyz");
} catch (NumberFormatException e) {
   log.error(e);
}

The name of the NumberFormatException class already tells you the kind of problem. Its message only needs to provide the input string that caused the problem.

If the name of the exception class isn’t that expressive, you need to provide the required information in the message.

17:17:26,386 ERROR Test Exception Handling:52-java.lang.Number Format Exception: For input string: “xyz”

2.6 Catch the Most Specific Exception First

Most IDEs help you with this best practice. They report an unreachable code block when you try to catch the less specific exception first.

The problem is that only the first catch block that matches the exception gets executed.

So, if you catch an IllegalArgumentException first, you will never reach the catch block that should handle the more specific NumberFormatException because it’s a subclass of the Illegal Argument Exception.

Always catch the most specific exception class first and add the less specific catch blocks to the end of your list.

You can see an example of such a try-catch statement in the following code snippet.

The first catch block handles all NumberFormatExceptions and the second one all IllegalArgumentExceptions which are not a NumberFormatException.

public void catchMostSpecificExceptionFirst() {
   try {
       doSomething("A message");
   } catch (NumberFormatException e) {
       log.error(e);
   } catch (IllegalArgumentException e) {
       log.error(e)
   }
}

2.7 Don’t Catch Throwable

Throwable is the superclass of all exceptions and errors. You can use it in a catch clause, but you should never do it!

If you use Throwable in a catch clause, it will not only catch all exceptions; it will also catch all errors. Errors are thrown by the JVM to indicate serious problems that are not intended to be handled by an application.

Typical examples for that are the OutOfMemoryError or the StackOverflowError. Both are caused by situations that are outside of the control of the application and can’t be handled.

So, better don’t catch a Throwable unless you’re absolutely sure that you’re in an exceptional situation in which you’re able or required to handle an error.

public void doNotCatchThrowable() {
   try {
       // do something
   } catch (Throwable t) {
       // don't do this!
   }
}

2.8 Don’t Ignore Exceptions

The developer was probably pretty sure that it would never be thrown and added a catch block that doesn’t handle or logs it. And when you find this block, you most likely even find one of the famous “This will never happen” comments.

public void doNotIgnoreExceptions() {
   try {
       // do something
   } catch (NumberFormatException e) {
       // this will never happen
 }
}

Well, you might be analyzing a problem in which the impossible happened.

So, please, never ignore an exception. You don’t know how the code will change in the future. Someone might remove the validation that prevented the exceptional event without recognizing that this creates a problem.

Or the code that throws the exception gets changed and now throws multiple exceptions of the same class, and the calling code doesn’t prevent all of them.

You should at least write a log message telling everyone that the unthinkable just had happened and that someone needs to check it.

public void logAnException() {

   try {

       // do something

   } catch (NumberFormatException e) {

       log.error("This should never happen: " + e);

   }

}

2.9 Don’t Log and Throw

That is probably the most often ignored best practice in this list. You can find lots of code snippets and even libraries in which an exception gets caught, logged and rethrown.

try {

   new Long("xyz");

} catch (NumberFormatException e) {

   log.error(e);

   throw e;

}

It might feel intuitive to log an exception when it occurred and then rethrow it so that the caller can handle it appropriately. But it will write multiple error messages for the same exception.

17:44:28,945 ERROR TestExceptionHandling:65 - java.lang.NumberFormatException: For input string: "xyz"

Exception in thread "main" java.lang.NumberFormatException: For input string: "xyz"

at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)

at java.lang.Long.parseLong(Long.java:589)

at java.lang.Long.(Long.java:965)

at com.stackify.example.TestExceptionHandling.logAndThrowException(TestExceptionHandling.java:63)

at com.stackify.example.TestExceptionHandling.main(TestExceptionHandling.java:58)

 

The additional messages also don’t add any information. As explained in best practice #4, the exception message should describe the exceptional event.

And the stack trace tells you in which class, method, and line the exception was thrown.

If you need to add additional information, you should catch the exception and wrap it in a custom one. But make sure to follow best practice number 9.

public void wrapException(String input) throws MyBusinessException {
   try {
       // do something
   } catch (NumberFormatException e) {
       throw new MyBusinessException("A message that describes the error.", e);
   }
}

So, only catch an exception if you want to handle it. Otherwise, specify it in the method signature and let the caller take care of it.

2.10 Wrap the Exception Without Consuming it

It’s sometimes better to catch a standard exception and to wrap it into a custom one. A typical example of such an exception is an application or framework-specific business exception.

That allows you to add additional information and you can also implement special handling for your exception class.

When you do that, make sure to set the original exception as the cause.

The Exception class provides specific constructor methods that accept a Throwable as a parameter.

Otherwise, you lose the stack trace and message of the original exception which will make it difficult to analyze the exceptional event that caused your exception.

public void wrapException(String input) throws MyBusinessException {
   try {
       // do something
   } catch (NumberFormatException e) {
       throw new MyBusinessException("A message that describes the error.", e);
   }
}

3. File Organization

Java source are named as *. java while the compiled Java byte code is named as *.class file. Each Java source file contains a single public class or interface. Each class must be placed in a separate file. This also applies to non-public classes too. 

If a file consists of sections, they should be separated by blank lines and an optional comment, identifying each section. Files longer than 2000 lines should be avoided.

Java classes should be packaged in a new java package for each self-contained project or group of related functionality.

Preferably there should be an HTML document file in each directory briefly outlining the purpose and structure of the package.

Java Source files should have the following ordering: Package and Import statements, beginning comments, Class and Interface Declarations.

There should not be any duplicate import statements. There should not be any hardcoded values in code. Max. No of Parameters in any class should be 12.

4. Source Code Style Guidelines

4.1 Beginning Comments 

All source files should begin with a c-style header as follows carrying the Title, Version, Date in mm/dd/yy format and the copyright information.

The header should be followed the package and import statements and then the documentation comments exactly in the following sequence and indented to the same level.

The tags see, since and deprecated are not mandatory and may be used when required.

4.2 Indentation

Four spaces should be used as the unit of indentation. The indentation pattern should be consistently followed throughout.

4.3 Left and Right braces 

The starting brace should be at the end of the conditional and the ending brace must be on a separate line and aligned with the conditional. It is strongly recommended that all conditional constructs define a block of code for single lines of code.

4.4 Wrapping Lines  

Lines longer than 80 characters should be avoided. When an expression will not fit on a single line, it should be broken according to these general principles:  

  • Break after a comma.  
  • Break after 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.  
  • If the above rules lead to confusing code or to code that’s squished up against the right margin, just indent 4 spaces instead.

4.5 White Space

Blank Lines

Blank lines improve readability by the setting of sections of code that are logically related.

Two blank lines should be used in the following circumstances:

  •  Between sections of a source file
  •  Between class and interface definitions

One blank line should always be used in the following circumstances:

    •  Between methods.
    •  Between the local variables in a method and its first statement.
    •  Before a block or single-line comment.
    •  Between logical sections inside a method to improve readability.
    • Before and after comments.

4.6 Blank Spaces

Blank spaces should be used in the following circumstances:

  • A keyword followed by a parenthesis should be separated by a space. Example: while (true)
  • A blank space should appear after commas in argument lists.
  • All binary operators except a period ‘.’ should be separated from their operands by spaces. Blank spaces should never separate unary operators such as unary minus, increment (“++”), and decrement (“–”) from their operands.
  • The expressions in a for statement should be separated by blank spaces.

Example:

  • Casts should be followed by a blank space.

 However blank space should not be used between a method name and its opening

parenthesis. This helps to distinguish keywords from method calls.

5. Implementation Comments

Java codes should have implementation comments delimited by /*…*/ or //. For commenting out code a double slash i.e. // is recommended, while for multiple or single-line comments given as an overview of code, the c-style comments i.e. /* */ should be used.

For clarity in code, comments should be followed by a blank line. Code should have four styles of implementation comments as follows and anything that goes against a standard should always be documented.

5.1 Block Comments

Block comments are used to provide descriptions of files, methods, data structures and algorithms. Block comments should be used at the beginning of each file and in places where code is to be explained.

They can be used in places such as before or within methods. Block comments inside a method should be indented to the same level as the code they describe.

A block comment should be preceded by a blank line to set it apart from the rest of the code. Block comments should be delimited by /*…*/.

During the process of development, the developer may need to leave some portions of the code to be reviewed and enhanced later. These portions should be specifically commented with a /* FIX ME */ tag specifying clearly the modifications to be made and the date of

marking. This construct should, however, be sparingly used. 

5.2 Single-Line & Trailing Comments

Short comments can appear on a single line indented to the level of the code that follows. A single-line comment may be preceded by a blank line if it gives clarity to code. It is recommended that single-line comments also be delimited by /*…*/.

Very short comments may appear on the same line as the code they describe but should be shifted far enough to separate them from the statements. They may be used for explaining the use of a variable or any statement and should also be delimited by /*…*/.

5.3 Commenting Codes

The // comment delimiter can comment out a complete line or only a partial line. It should not be used on consecutive multiple lines for text comments, however, it may be used in single or consecutive multiple lines for commenting out sections of code.

5.4 Documentation Comment

Java codes should have documentation comments delimited by /**…*/. Documentation comments are meant to describe the specification of the code, from an implementation-free perspective to be read by developers who might not necessarily have the source code at hand.

Simple Documentation comments should add to the clarity of code and should be followed by a blank line.

5.5 Classes and Interfaces

All comments using Javadoc conventions should be shown. Each class should be documented describing the purpose of the class, guaranteed invariants, usage instructions, and/or usage examples.

5.6 Variables

First, the static variables should be declared in the sequence public also all the static variables defined before the methods in the classes, then protected, then package level and then the private followed by instance variables in the same sequence.

Nature, purpose, constraints, and usage of static and instances variables should be documented using Javadoc conventions.

A blank line should follow the declarations.

5.7 Operators

The parenthesis should be effectively used to avoid operator precedence.

5.8 Methods

Each method should declare the Javadoc tags exactly in the sequence as given below. Each line item begins with an asterisk.

All subsequent lines in the multiline component are to be indented so that they line up vertically with the previous line. For reference, the Javadoc tags are explained in detail in Annexure.

5.9 Description

Every method should include a header at the top of the source code that documents all of the information that is critical to understanding it.

A detailed description of the method may include the intent of method i.e. what and why the method does, what a method should be passed as parameters and what it returns, any Known bugs, exceptions that the method throws, information on visibility decisions., how a method changes the object, pre and post conditions, side effects, dependencies, implementation notes, who should be calling this method, whether the method should or should not be overridden, were to invoke super when overriding, control flow or state dependencies that need to exist before calling this method.

PARAMETER SECTION

Describes the type, class, or protocol of all the methods or routine arguments. Should describe the parameters intended use and constraints. Every function parameter value should be checked before being used (Usually check for nulls and Data Validation).

EXAMPLE:

RETURNS SECTION

This section is used to describe the method return type. Specifically, it needs to detail the actual data type returned, the range of possible return values, and where applicable, error information returned by the method.

Every function should return the correct value at every function return point or throw correct Exceptions in case of Errors.

Example:

* @return Possible values are 1..n.

EXCEPTION SECTION

The purpose section is a complete description of all the non-system exceptions that this method throws.

A description of whether the exception is recoverable or not should also be included. If applicable, a recovery strategy for the exception can be described here.

In addition to the method documentation, it is also required to include comments within the methods to make it easier to understand, maintain, and enhance.

  • The control structures i.e. what each control structure, such as loop, does should be documented.
  • Any assumptions or calculations should be documented.
  • Each local variable should have an end line comment describing its use.
  • Any complex code in a method should be documented if it is not obvious.
  • If there are statements that must be executed in a defined order then this fact should be documented.

6. Declarations

One declaration per line is recommended since it encourages commenting and enhances the clarity of code. The order and position of declaration should be as follows:

First, the static/class variables should be placed in the sequence: First public class variables, protected, package/default level i.e. with no access modifier and then the private.

As far as possible static or class fields should be explicitly instantiated by the use of static initializers because instances of a class may sometimes not be created before a static field is accessed.

  • Instance variables should be placed in the sequence: First public instance variables, protected,
  • package level with no access modifier and then private.
  • Next, class constructors should be declared.
  • This should be followed by the inner classes, if applicable
  • Class methods should be grouped by functionality rather than by scope or accessibility to make
  • reading and understanding the code easier.
  • Declarations for local variables should be only at the beginning of blocks e.g. at the beginning of a try-catch construct.
  • Local declarations that hide declarations at higher levels should be avoided. For example, the same variable name in an inner block.
  •  Numerical constants should not be coded directly except 1, 0, -1.

7. Standards for Statements

Each line should contain at most one statement. While compound statements are statements that contain lists of statements enclosed in braces. The enclosed statements should be indented one more

level than the compound statement. The opening brace should be at the end of the line that begins the compound statement. The closing brace should begin a line and be indented to the beginning of the compound statement.

Braces should be used around all statements, even single statements, when they are part of a control structure, such as an if-else or for statement.

A boolean expression/function should only be compared to a boolean constant. goto statements should be avoided. Try to move invariable computation outside the loop. 

E.g. D += 9*24*pie *x

Where pie is a constant then 9*24*pie can be moved out and assigned to a local variable and used inside a loop where x changes in the loop

  • return Statements 

A return statement with a value should not use parentheses unless they make the return value more

obvious in some way.

Example:

  • if, if-else Statements

The ‘if’ keyword and conditional expression must be placed on the same line. The if statements must

always use braces {}

Example:

  • for Statements

A for statement should have the following form:

When using the comma operator in the initialization or update clause of a for  statement, avoid the complexity of using more than three variables.

If needed, separate statements before the for loop (for the initialization clause) or at the end of the loop (for the update clause) may be used.

The keyword ‘for’ and the parenthesis should be separated by a space and the expressions in a for statement should be separated by blank space.

The statement block is placed on the next line. The closing curly brace starts in a new line, indented to match its corresponding opening statement.

  • while Statements

The ‘while’ construct uses the same layout format as the ‘if’ construct. The ‘while’ keyword should appear on its own line, immediately followed by the conditional expression.

The keyword ‘while’ and the parenthesis should be separated by a space. The statement block is placed on the next line. The closing curly brace starts in a new line, indented to match its corresponding opening statement.

Example:

  • do-while Statements

The DO..WHILE form of the while construct should appear as shown below:

Examples:

The statement block is placed on the next line. The closing curly brace starts in a new line, indented to match its corresponding opening statement.

  • switch Statements

The ‘switch’ construct should use the same layout format as the ‘if’ construct. The ‘switch’ keyword should appear on its own line, immediately followed by its test expression. The keyword ‘switch’ and the parenthesis should be separated by a space. 

The statement block should be placed on the next line. The closing curly brace starts in a new line, indented to match its corresponding opening statement.

Every time a case falls through i.e. does not include a break statement, a comment should be added where the break statement would normally be.

Every switch statement must include a default case. A break in the default case is redundant, but it prevents an error if another case is added later and therefore may be added.

All missing switch case break statements should be correct and marked with a comment.

Examples:

  • try-catch Statements

In the try/catch construct the ‘try’ keyword should be followed by the open brace in its own line. This is followed by the statement body and the close brace on its own line.

This may follow any number of ‘catch’ phrases – consisting of the ‘catch’ keyword and the exception expression on its own line with the ‘catch’ body; followed by the close brace on its own line.

Try-catch should be accomplished with finally block to destroys all Objects not required. There should not be any empty try-catch blocks.

Example:

7. Naming Conventions

Naming conventions make programs more understandable by making them easier to read. Following conventions should be followed while naming a class or a member:

  • Use full English descriptors that accurately describe the variable, method or class. For example, the use of names like totalSales, currentDate instead of names like x1, y1, or fn.
  • Terminology applicable to the domain should be used. Implying that if user refers to clients as customers, then the term Customer should be used for the class, not Client.
  • The mixed-case should be used to make names readable with lower case letters, in general, capitalizing the first letter of class names and interface names.
  • Abbreviations should not be used as far as possible, but if used, should be documented and consistently used.
  • Very long or similar names for classes or methods should be avoided.  
  • Standard acronyms such as SQL should also be represented in the mixed case as sqlDatabase().

7.1 Standards for Methods

  • Naming Methods

Methods should be named using a full English description, using mixed case with the first letter of any non-initial word capitalized. It is also common practice for the first word of a method name to be a strong, active verbs. e.g. getValue(), printData(), save() ,delete().

This convention results in methods whose purpose can often be determined just by looking at its name. It is recommended that accessor methods be used to improve the maintainability of classes.

  • Getters

Getters are methods that return the value of a field. The word ‘get’ should be prefixed to the name of the field, unless it is a boolean field where ‘is’ should be prefixed to the name of the field . e.g. getTotalSales(), isPersistent().

Alternately the prefix ‘has’ or ‘can’ instead of ‘is’ for boolean getters may be used. For example, getter names such as hasDependents() and canPrint() can be created.

Getters should always be made protected, so that only subclasses can access the fields except when an ‘outside class’ needs to access the field when the getter

method may be made public and the setter protected.

  • Setters

Setters, also known as mutators, are methods that modify the values of a field. The word ‘set’ should be prefixed to the name of the field for such methods type. Example: setTotalSales(),setPersistent(boolean isPersistent)

  • Getters for Constants

Constant values may need to be changed over a period of time. Therefore constants should be implemented as getter methods. By using accessors for constants there is only one source to retrieve the value. This increases the maintainability of the system.

  • Accessors for Collections

The main purpose of accessors is to encapsulate the access to fields.

Collections, such as arrays and vectors need to have getter and setter method and as it is possible to add and remove to and from collections, accessor methods need to be included to do so.

The advantage of this approach is that the collection is fully encapsulated, allowing changes later like replacing it with another structure, like a linked list.

Examples: getOrderItems(), setOrderItems(), insertOrderItem(), deleteOrderItem(), newOrderItem()

  • Method Visibility

For a good design, the rule is to be as restrictive as possible when setting the visibility of a method. If a method doesn’t have to be private then it should have default access modifier, if it doesn’ t have to be

default then it should be made protected and if it doesn’ t have to protected only then it should be made public. Wherever a method is made more visible it should be documented why.

Access modifiers for methods should be explicitly mentioned in cases like interfaces where the default permissible access modifier is public.

7.2 Standards for Parameters (Arguments) To Methods

Parameters should be named following the same conventions as for local variables. Parameters to a method are documented in the header documentation for the method using the javadoc@param tag.

However:

  • Cascading method calls like method1().method2() should be avoided.
  • Overloading methods on argument type should be avoided.
  • It should be declared when a class or method is thread-safe.
  • Synchronized methods should be preferred over synchronized blocks.
  • The fact that a method invokes wait should always be documented
  • Abstract methods should be preferred in base classes over those with default no-op implementations.
  • All possible overflow or underflow conditions should be checked for a computation.

There should be no space between a method/constructor name and the parenthesis but there should be a blank space after commas in argument lists.

9. Naming Convention standards

9.1 Naming Variables

Use a full English descriptor for variable names to make it obvious what the field represents.

Fields, that are collections, such as arrays or vectors, should be given names that are plural to indicate that they represent multiple values. Variable names should not start with an

underscore _ or dollar sign $ characters and should be short and meaningful. The choice of a variable name should be mnemonic i.e., designed to indicate to the casual observer the intent of its use. Single character variable names should be avoided except for temporary

“throwaway” variables.

9.2 Naming Components

For names of components, full English descriptor should be used, postfixed by the Component type.

This makes it easy to identify the purpose of the component as well as its type, making it easier to find each component in a list. Therefore names like NewHelpMenuItem, CloseButton should be preferred over Button1, Button2, etc.

9.3 Naming Constants

Constants, whose values that do not change, are typically implemented as static final fields of classes. They should be represented with full English words, all in uppercase, with underscores between the words like FINAL_VALUE.

9.4 Naming Collections

A collection, such as an array or a vector, should be given a pluralized name representing the types of objects stored by the array. The name should be a full English descriptor with the first letter of all non-initial words capitalized like customers, orderItems, aliases

9.5 Naming Local Variables

In general, local variables are named following the same conventions as used for fields, in other words use of full English descriptors with the first letter of any non-initial word in uppercase.

For the sake of convenience, however, this naming convention is relaxed for several specific types of local variable like Streams, Loop counters, Exceptions.Name hiding or data hiding refers to the practice of naming a local variable, argument, or methods the same or similar as that of another one of greater scope in same or super class.

This may lead to confusion and should be avoided.

9.6 Naming Streams

When there is a single input and/or output stream being opened, used, and then closed within a method the common convention is to use ‘in’ and ‘out’ for the names of these streams, respectively. 

9.7 Naming Loop Counters

Loop counters are a very common use for local variables therefore the use of i, j, or k, is acceptable for loop counters where they are obvious. However, if these names are used for loop counters, they should be used consistently. For complex nested loops the counters should be given full meaningful English descriptors.

10. Variable Assignments  

Assigning several variables to the same value in a single statement should be avoided, i.e., we should avoid constructs like var1 = var2 = var3 = 0;  

Assignment operator should not be used in a place where it can be easily confused with the equality operator.  

Embedded assignments in an attempt to improve run-time performance should be avoided 

  • Variable Visibility

     

For reasons of encapsulation, fields should not be declared public. All fields should be declared private unless necessary otherwise.

Fields should never be accessed directly, instead accessor methods should be used i.e. private members should be accessed through methods. All fields should be declared private and accessed by getter and setter methods also called accessors.  

  • Documenting & Declaring a Variable 

Every field should be documented well enough so that other developers can understand it. There is a need to document description, all applicable invariants, visibility decisions. Wherever a field is made more visible it should be documented why. There are some conventions regarding the declaration and documentation of local variable. These conventions are:  

  • Declare one local variable per line of code.  
  • Document local variables with an end line comment.  
  • Declare local variables at the top of the block of code. 
  •  Use local variables for one thing only at a time. 
  •  However the following should be taken into consideration while using variables:  
  • Instance variables should not be declared public. 
  •  Implicit initializers for static or instance variables should not be relied and initialization should be explicit. 
  •  Use of static should be minimized as they act like globals. They make methods more context dependent, hide possible side effects, sometimes present synchronized access problems and are the source of fragile, non-extensible constructions. Also, neither static variables nor methods are overridable in any useful sense in subclasses.  
  • Generally prefer double to float and use int for compatibility with standard Java constructs and classes. 
  •  Use final and/or comment conventions to indicate whether instance variables that never have their values changed after construction are intended to be constant (immutable) for the lifetime of the object.  
  • 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.  
  • Assign null to any reference variable that is no longer being used to enable garbage collection.  
  • Same names of variables or methods should be avoided in methods and subclasses

11. Best Practices

11.1 Efficient String Concatenation:- For making a long string by adding different small strings always use append method of java.lang.StringBuffer and never use ordinary ‘+’ operator for adding up strings. 

11.2 Optimal Use Of Garbage Collector:- For easing out the work of java Garbage Collector always set all referenced variables used to ‘null’ explicitly thus de-referencing the object which is no more required by the application and allowing Garbage Collector to swap away that variable thus realizing memory. 

11.3 Writing Oracle Stored Procedures Optimally:- Avoid using ‘IN’ and ‘NOT IN’ clause and rather try to use ‘OR’ operator for increasing the response time for the Oracle Stored Procedures. 

11.4 Using variables in any Code Optimally:- Try to make minimum number of variables in JSP/Java class and try to use already made variables in different algorithms shared in the same JSP/Java class by setting already populated variable to ‘null’ and then again populating that variable with new value and then reusing them.

Do You Need Help With Your Java-based Applications?

If you need expert help in developing your Java-based applications then you can count on Perfomatix.

We constantly focuses on identifying the best Java coding practices to improve the quality and implementing them while developing a software application.

Feel free to drop in a note for us right now. Talk to our experts now and let us be your innovation partner!

Perfomatix | Product Engineering Services Company