1. [Mandatory] A static field or method should be directly referred to by its class name instead of its corresponding object name.

2. [Mandatory] An overridden method from an interface or abstract class must be marked with @Override annotation.

Counter example: For getObject() and get0bject(), the first one has a letter ‘O’, and the second one has a number ‘0’. To accurately determine whether the overriding is successful, an @Override annotation is necessary. Meanwhile, once the method signature in the abstract class is changed, the implementation class will report a compile-time error immediately.

3. [Mandatory] varargs is recommended only if all parameters are of the same type and semantics. Parameters with Object type should be avoided.

Note: Arguments with the varargs feature must be at the end of the argument list. (Programming with the varargs feature is not recommended.)

Positive example:

  1. public User getUsers(String type, Integer... ids);

4. [Mandatory] Modifying the method signature is forbidden to avoid affecting the caller. A @Deprecated annotation with an explicit description of the new service is necessary when an interface is deprecated.

5. [Mandatory] Using a deprecated class or method is prohibited.

Note: For example, decode(String source, String encode) should be used instead of the deprecated method decode(String encodeStr). Once an interface has been deprecated, the interface provider has the obligation to provide a new one. At the same time, client programmers have the obligation to use the new interface.

6. [Mandatory] Since NullPointerException can possibly be thrown while calling the equals method of Object, equals should be invoked by a constant or an object that is definitely not null.

Positive example: "test".equals(object);

Counter example: object.equals("test");

Note: java.util.Objects#equals (a utility class in JDK7) is recommended.

7. [Mandatory] Use the equals method, rather than reference equality ‘==’, to compare primitive wrapper classes.

Note: Consider this assignment: Integer var = ?. When it fits the range from -128 to 127, we can use == directly for a comparison. Because the Integer object will be generated by IntegerCache.cache, which reuses an existing object. Nevertheless, when it fits the complementary set of the former range, the Integer object will be allocated in the heap, which does not reuse an existing object. This is a pitfall. Hence the equals method is recommended.

8. [Mandatory] Rules for using primitive data types and wrapper classes:
  1) Members of a POJO class must be wrapper classes.
  2) The return value and arguments of a RPC method must be wrapper classes.
  3) [Recommended] Local variables should be primitive data types.
  Note: In order to remind the consumer of explicit assignments, there are no initial values for members in a POJO class. As a consumer, you should check problems such as NullPointerException and warehouse entries for yourself.
  Positive example: As the result of a database query may be null, assigning it to a primitive date type will cause a risk of NullPointerException because of autoboxing.
  Counter example: Consider the output of a transaction volume’s amplitude, like ±x%. As a primitive data, when it comes to a failure of calling a RPC service, the default return value: 0% will be assigned, which is not correct. A hyphen like - should be assigned instead. Therefore, the null value of a wrapper class can represent additional information, such as a failure of calling a RPC service, an abnormal exit, etc.

9. [Mandatory] While defining POJO classes like DO, DTO, VO, etc., do not assign any default values to the members.

10. [Mandatory] To avoid a deserialization failure, do not change the serialVersionUID when a serialized class needs to be updated, such as adding some new members. If a completely incompatible update is needed, change the value of serialVersionUID in case of a confusion when deserialized.

Note: The inconsistency of serialVersionUID may cause an InvalidClassException at runtime.

11. [Mandatory] Business logic in constructor methods is prohibited. All initializations should be implemented in the init method.

12. [Mandatory] The toString method must be implemented in a POJO class. The super.toString method should be called in in the beginning of the implementation if the current class extends another POJO class.

Note: We can call the toString method in a POJO directly to print property values in order to check the problem when a method throws an exception in runtime.

13. [Recommended] When accessing an array generated by the split method in String using an index, make sure to check the last separator whether it is null to avoid IndexOutOfBoundException.

Note:

  1. String str = "a,b,c,,";
  2. String[] ary = str.split(",");
  3. // The expected result exceeds 3. However it turns out to be 3.
  4. System.out.println(ary.length);

14. [Recommended] Multiple constructor methods or homonymous methods in a class should be put together for better readability.

15. [Recommended] The order of methods declared within a class is:
public or protected methods -> private methods -> getter/setter methods.

Note: As the most concerned ones for consumers and providers, public methods should be put on the first screen. Protected methods are only cared for by the subclasses, but they have chances to be vital when it comes to Template Design Pattern. Private methods, the black-box approaches, basically are not significant to clients. Getter/setter methods of a Service or a DAO should be put at the end of the class implementation because of the low significance.

16. [Recommended] For a setter method, the argument name should be the same as the field name. Implementations of business logics in getter/setter methods, which will increase difficulties of the troubleshooting, are not recommended.

Counter example:

  1. public Integer getData() {
  2. if (true) {
  3. return data + 100;
  4. } else {
  5. return data - 100;
  6. }
  7. }

17. [Recommended] Use the append method in StringBuilder inside a loop body when concatenating multiple strings.

Counter example:

  1. String str = "start";
  2. for (int i = 0; i < 100; i++) {
  3. str = str + "hello";
  4. }

Note: According to the decompiled bytecode file, for each loop, it allocates a StringBuilder object, appends a string, and finally returns a String object via the toString method. This is a tremendous waste of memory.

18. [Recommended] Keyword final should be used in the following situations:
  1) A class which is not allow to be inherited, or a local variable not to be reassigned.
  2) An argument which is not allow to be modified.
  3) A method which is not allow to be overridden.

19. [Recommended] Be cautious to copy an object using the clone method in Object.

Note: The default implementation of clone in Object is a shallow (not deep) copy, which copies fields as pointers to the same objects in memory.

20. [Recommended] Define the access level of members in class with severe restrictions:
  1) Constructor methods must be private if an allocation using new keyword outside of the class is forbidden.
  2) Constructor methods are not allowed to be public or default in a utility class.
  3) Nonstatic class variables that are accessed from inheritants must be protected.
  4) Nonstatic class variables that no one can access except the class that contains them must be private.
  5) Static variables that no one can access except the class that contains them must be private.
  6) Static variables should be considered in determining whether they are final.
  7) Class methods that no one can access except the class that contains them must be private.
  8) Class methods that are accessed from inheritants must be protected.

Note: We should strictly control the access for any classes, methods, arguments and variables. Loose access control causes harmful coupling of modules. Imagine the following situations. For a private class member, we can remove it as soon as we want. However, when it comes to a public class member, we have to think twice before any updates happen to it.