1. [Mandatory] Do not catch Runtime exceptions defined in JDK, such as NullPointerException
and IndexOutOfBoundsException
. Instead, pre-check is recommended whenever possible.
Note: Use try-catch only if it is difficult to deal with pre-check, such as
NumberFormatException
.Positive example:
if (obj != null) {...}
Counter example:
try { obj.method() } catch(NullPointerException e){…}
2. [Mandatory] Never use exceptions for ordinary control flow. It is ineffective and unreadable.
3. [Mandatory] It is irresponsible to use a try-catch on a big chunk of code. Be clear about the stable and unstable code when using try-catch. The stable code that means no exception will throw. For the unstable code, catch as specific as possible for exception handling.
4. [Mandatory] Do not suppress or ignore exceptions. If you do not want to handle it, then re-throw it. The top layer must handle the exception and translate it into what the user can understand.
5. [Mandatory] Make sure to invoke the rollback if a method throws an Exception.
6. [Mandatory] Closeable resources (stream, connection, etc.) must be handled in finally block. Never throw any exception from a finally block.
Note: Use the try-with-resources statement to safely handle closeable resources (Java 7+).
7. [Mandatory] Never use return within a finally block. A return statement in a finally block will cause exceptions or result in a discarded return value in the try-catch block.
8. [Mandatory] The Exception type to be caught needs to be the same class or superclass of the type that has been thrown.
9. [Recommended] The return value of a method can be null. It is not mandatory to return an empty collection or object. Specify in Javadoc explicitly when the method might return null. The caller needs to make a null check to prevent NullPointerException
.
Note: It is caller’s responsibility to check the return value, as well as to consider the possibility that remote call fails or other runtime exception occurs.
10. [Recommended] One of the most common errors is NullPointerException
. Pay attention to the following situations:
1) If the return type is primitive, return a value of wrapper class may cause NullPointerException
.
Counter example: public int f() { return Integer }
Unboxing a null value will throw a NullPointerException
.
2) The return value of a database query might be null.
3) Elements in collection may be null, even though Collection.isEmpty()
returns false.
4) Return values from an RPC might be null.
5) Data stored in sessions might by null.
6) Method chaining, like obj.getA().getB().getC()
, is likely to cause NullPointerException
.
Positive example: Use Optional
to avoid null check and NPE (Java 8+).
11. [Recommended] Use “throw exception” or “return error code”. For HTTP or open API providers, “error code” must be used. It is recommended to throw exceptions inside an application. For cross-application RPC calls, result is preferred by encapsulating isSuccess, error code and brief error messages.
Note: Benefits to return Result for the RPC methods:
1) Using the ‘throw exception’ method will occur a runtime error if the exception is not caught.
2) If stack information it not attached, allocating custom exceptions with simple error message is not helpful to solve the problem. If stack information is attached, data serialization and transmission performance loss are also problems when frequent error occurs.
12. [Recommended] Do not throw RuntimeException
, Exception
, or Throwable
directly. It is recommended to use well defined custom exceptions such as DAOException
, ServiceException
, etc.
13. [For Reference] Avoid duplicate code (Do not Repeat Yourself, also known as DRY principle).
Note: Copying and pasting code arbitrarily will inevitably lead to duplicated code. If you keep logic in one place, it is easier to change when needed. If necessary, extract common codes to methods, abstract classes or even shared modules.
Positive example: For a class with a number of public methods that validate parameters in the same way, it is better to extract a method like:
private boolean checkParam (DTO dto) {
...
}