README.md 17.6 KB
Newer Older
骏烈 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13
# P3C-PMD

## <font color="green">Build requirements</font>
- JDK 1.7+
- Maven 3

## <font color="green">Use as dependency</font>

### <font color="green">Maven</font>
```xml
<dependency>
    <groupId>com.alibaba.p3c</groupId>
    <artifactId>p3c-pmd</artifactId>
J
jimin 已提交
14
    <version>1.3.6</version>
骏烈 已提交
15 16 17
</dependency>
```
### <font color="green">Gradle</font>
18
```groovy
J
jimin 已提交
19
compile 'com.alibaba.p3c:p3c-pmd:1.3.6'
骏烈 已提交
20 21 22 23
```

## <font color="green">Rules</font>

玄坛 已提交
24
P3C-PMD implements 54 rules involved in *Alibaba Java Coding Guidelines*, based on PMD ([https://github.com/pmd/pmd](https://github.com/pmd/pmd)).
骏烈 已提交
25 26

### <font color="green">Concurrency</font>
27
* 1 ``[Mandatory]`` Customized ThreadLocal variables must be recycled, especially when using thread pools in which threads are often reused. Otherwise, it may affect subsequent business logic and cause unexpected problems such as memory leak.
骏烈 已提交
28 29 30
* 2 ``[Mandatory]`` A meaningful thread name is helpful to trace the error information, so assign a name when creating threads or thread pools.  
Positive example:

骏烈 已提交
31 32 33 34 35
    ```java
    public class TimerTaskThread extends Thread {
        public TimerTaskThread(){
            super.setName("TimerTaskThread"); … }
    ```
骏烈 已提交
36 37
* 3 ``[Mandatory]`` Threads should be provided by thread pools. Explicitly creating threads is not allowed. 
Note: Using thread pool can reduce the time of creating and destroying thread and save system resource. If we do not use thread pools, lots of similar threads will be created which lead to "running out of memory" or over-switching problems.
38
* 4 ``[Mandatory]`` A thread pool should be created by ThreadPoolExecutor rather than Executors. These would make the parameters of the thread pool understandable. It would also reduce the risk of running out of system resources.
骏烈 已提交
39
Note: Below are the problems created by usage of Executors for thread pool creation:  
骏烈 已提交
40 41 42 43
    1. FixedThreadPool and SingleThreadPool:
         Maximum request queue size Integer.MAX_VALUE. A large number of requests might cause OOM.
    2. CachedThreadPool and ScheduledThreadPool:  
        The number of threads which are allowed to be created is Integer.MAX_VALUE. Creating too many threads might lead to OOM.
44 45
* 5 ``[Mandatory]`` SimpleDataFormat is unsafe, do not define it as a static variable. If you have to, lock or Apache DateUtils class must be used.
Positive example: Pay attention to thread-safety when using DateUtils. It is recommended to use below:
骏烈 已提交
46

骏烈 已提交
47 48 49 50 51 52 53 54 55
    ```java
    private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() {  
        @Override  
        protected DateFormat initialValue() {  
            return new SimpleDateFormat("yyyy-MM-dd");  
        }  
    };  
    ```
    Note: In JDK8, Instant can be used to replace Date; likewise Calendar is replaced by LocalDateTime, and SimpleDateFormatter is replaced by DateTimeFormatter.
56 57 58 59
* 6 ``[Mandatory]`` Run multiple TimeTask by using ScheduledExecutorService rather than Timer, because Timer will kill all running threads in case of failure to catch exceptions.
* 7 ``[Recommended]`` When using CountDownLatch to convert asynchronous operations to synchronous ones, each thread must call countdown method before quitting. Make sure to catch any exception during thread running, to let countdown method be executed. If main thread cannot reach await method, program will return until timeout.
Note: Be careful, exception thrown by a child thread cannot be caught by main thread.
* 8 ``[Recommended]`` Avoid using Random instance by multiple threads. Although it is thread-safe, competition on the same seed will damage performance.
骏烈 已提交
60 61
Note: Random instance includes instances of java.util.Random and Math.random().  
Positive example:  
62
After JDK7, ThreadLocalRandom API can be used directly. But before JDK7, instance needs to be created in each thread.
骏烈 已提交
63 64 65

### <font color="green">Collection</font>

66
* 1 ``[Mandatory]`` Do not cast subList in class ArrayList, otherwise ClassCastException will be thrown: java.util.RandomAccessSubList cannot be cast to java.util.ArrayList.  
骏烈 已提交
67
Note: subList of ArrayList is an inner class, which is a view of ArrayList. All operations on the Sublist will affect the original list finally.
68 69
* 2 ``[Mandatory]`` When using subList, be careful while modifying the size of original list. It might cause ConcurrentModificationException when performing traversing, adding or deleting on the subList.
* 3 ``[Mandatory]`` Use toArray(T[] array) to convert list to array. The input array type should be the same with the list whose size is list.size().
骏烈 已提交
70 71 72
Counter example: Do not use toArray method without arguments. Since the return type is Object[], ClassCastException will be thrown when casting it to a different array type.
Positive example:

骏烈 已提交
73 74 75 76 77 78 79
    ```java
        List<String> list = new ArrayList<String>(2);
        list.add("guan");
        list.add("bao");        
        String[] array = new String[list.size()];
        array = list.toArray(array);
    ```
骏烈 已提交
80
Note: When using toArray method with arguments, if input array size is not large enough, the method will re-assign the size internally, and then return the address of new array. If the size is larger than needed, the value of index[list.size()] will be set to null while other values remain the same. Defining an input with the same size of the list is recommended.
81
* 4 ``[Mandatory]`` Do not use methods which will modify the list after using Arrays.asList to convert array to list, otherwise methods like add/remove/clear will throw UnsupportedOperationException.
骏烈 已提交
82 83
Note: The result of asList is the inner class of Arrays, which does not implement methods to modify itself. Arrays.asList is only a transferred interface, data inside which is stored as an array.

骏烈 已提交
84 85 86 87
    ```java
    String[] str = new String[] { "a", "b" };
    List<String> list = Arrays.asList(str); 
    ```
骏烈 已提交
88 89
Case 1: list.add("c"); will throw a runtime exception.  
Case 2: str[0]= "gujin"; list.get(0) will be modified.
90
* 5 ``[Mandatory]`` Do not remove or add elements to a collection in a foreach loop. Please use Iterator to remove an item. Iterator object should be synchronized when executing concurrent operations.  
骏烈 已提交
91 92
Counter example:

骏烈 已提交
93 94 95 96 97 98 99 100 101 102 103
    ```java
    List<String> a = new ArrayList<String>();
    a.add("1");
    a.add("2");
    for (String temp : a) {
        if ("1".equals(temp)) {
            a.remove(temp);
        }
    }
    ```
    Note: If you try to replace "1" with "2", you will get an unexpected result.
骏烈 已提交
104 105
Positive example:

骏烈 已提交
106 107 108 109 110 111 112 113 114
    ```java
    Iterator<String> it = a.iterator();
    while (it.hasNext()) {    
            String temp =  it.next();             
            if (delete condition) {              
                  it.remove();       
            }
        }    
    ```
115
* 6``[Recommended]`` Set a size when initializing a collection if possible.  
骏烈 已提交
116 117 118 119
Note: Better to use ArrayList(int initialCapacity) to initialize ArrayList.


### <font color="green">Naming Conventions</font>
120
* 1 ``[Mandatory]`` No identifier name should start or end with an underline or a dollar sign.  
骏烈 已提交
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
Counter example: _name / __name / $Object / name_ / name$ / Object$

* 2 ``[Mandatory]`` Using Chinese, Pinyin, or Pinyin-English mixed spelling in naming is strictly prohibited. Accurate English spelling and grammar will make the code readable, understandable, and maintainable.
Positive example: alibaba / taobao / youku / Hangzhou. In these cases, Chinese proper names in Pinyin are acceptable.

* 3 ``[Mandatory]`` Class names should be nouns in UpperCamelCase except domain models: DO, BO, DTO, VO, etc.
Positive example: MarcoPolo / UserDO / HtmlDTO / XmlService / TcpUdpDeal / TaPromotion
Counter example: macroPolo / UserDo / HTMLDto / XMLService / TCPUDPDeal / TAPromotion

* 4 ``[Mandatory]`` Method names, parameter names, member variable names, and local variable names should be written in lowerCamelCase.
Positive example: localValue / getHttpMessage() / inputUserId

* 5 ``[Mandatory]`` Constant variable names should be written in upper characters separated by underscores. These names should be semantically complete and clear.
Positive example: MAX_STOCK_COUNT
Counter example: MAX_COUNT

137
* 6 ``[Mandatory]`` Abstract class names must start with Abstract or Base. Exception class names must end with Exception. Test cases shall start with the class names to be tested and end with Test.
骏烈 已提交
138 139 140 141 142 143

* 7 ``[Mandatory]`` Brackets are a part of an Array type. The definition could be: String[] args;
Counter example: String args[];

* 8 ``[Mandatory]`` Do not add 'is' as prefix while defining Boolean variable, since it may cause a serialization exception in some Java Frameworks.
Counter example: boolean isSuccess; The method name will be isSuccess() and then RPC framework will deduce the variable name as 'success', resulting in a serialization error since it cannot find the correct attribute.
144

骏烈 已提交
145 146
* 9 ``[Mandatory]`` Package should be named in lowercase characters. There should be only one English word after each dot. Package names are always in singular format while class name can be in plural format if necessary.  
Positive example: com.alibaba.open.util can be used as package name for utils;
147
* 10 There are mainly two rules for interface and corresponding implementation class naming:
骏烈 已提交
148
    1. ``[Mandatory]`` All Service and DAO classes must be interface based on SOA principle. Implementation class names should be ended with Impl.  
骏烈 已提交
149
Positive example: CacheServiceImpl to implement CacheService.
骏烈 已提交
150
    2. ``[Recommended]`` If the interface name is to indicate the ability of the interface, then its name should be adjective.  
骏烈 已提交
151 152 153 154 155 156 157 158 159
Positive example: AbstractTranslator to implement Translatable.

### <font color="green">Constant Conventions</font>

* 1 ``[Mandatory]`` Magic values, except for predefined, are forbidden in coding.
Counter example: String key="Id#taobao_" + tradeId;
* 2 ``[Mandatory]`` 'L' instead of 'l' should be used for long or Long variable because 'l' is easily to be regarded as number 1 in mistake.  
Counter example: Long a=2l, it is hard to tell whether it is number 21 or Long 2.
### <font color="green">OOP</font>
160
* 3 ``[Mandatory]`` Using a deprecated class or method is prohibited.  
骏烈 已提交
161
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 check out what its new implementation is.
162
* 4 ``[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.  
骏烈 已提交
163 164 165 166
Positive example: "test".equals(object);  
Counter example: object.equals("test");  
Note: java.util.Objects#equals (a utility class in JDK7) is recommended.

167 168 169
* 5 ``[Mandatory]`` The wrapper classes should be compared by equals method rather than by symbol of '==' directly.  
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 Heap, which does not reuse an existing object. This is an [implementation-level detail](https://docs.oracle.com/javase/specs/jls/se9/html/jls-5.html#jls-5.1.7-300) that should NOT be relied upon. Hence using the equals method is always recommended.
* 6 ``[Mandatory]`` Rules for using primitive data types and wrapper classes:
骏烈 已提交
170 171 172
    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.    
骏烈 已提交
173
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.
174
 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 Unboxing.  
骏烈 已提交
175
 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.
176 177
* 7 ``[Mandatory]`` While defining POJO classes like DO, DTO, VO, etc., do not assign any default values to the members.  
* 8 ``[Mandatory]`` The toString method must be implemented in a POJO class. The super.toString method should be called in front of the whole implementation if the current class extends another POJO class.  
骏烈 已提交
178
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.
179
* 9 ``[Recommended]`` Use the append method in StringBuilder inside a loop body when concatenating multiple strings.  
骏烈 已提交
180

骏烈 已提交
181
    Counter example:
骏烈 已提交
182

骏烈 已提交
183
    ```java
骏烈 已提交
184 185 186 187
    String str = "start";  
    for(int i=0; i<100; i++) {  
        str = str + "hello";  
    }
骏烈 已提交
188 189 190
    ```
    
    Note: According to the decompiled bytecode file, for each iteration, it allocates a new StringBuilder object, appends a string, and finally returns a String object via the toString method. This is a tremendous waste of memory, especially when the iteration count is large.
骏烈 已提交
191 192 193 194 195

### <font color="green">Flow Control Statements</font>
* 1 ``[Mandatory]`` In a switch block, each case should be finished by break/return. If not, a note should be included to describe at which case it will stop. Within every switch block, a default statement must be present, even if it is empty.
* 2 ``[Mandatory]`` Braces are used with if, else, for, do and while statements, even if the body contains only a single statement. Avoid using the following example:

骏烈 已提交
196 197 198
    ```java
    if (condition) statements; 
    ```
199 200
* 3 ``[Recommended]`` Do not use complicated expressions in conditional statements (except for frequently used methods like getXxx/isXxx). Using boolean variables to store results of complicated expressions temporarily will increase the code's readability.
Note: Logic within many if statements are very complicated. Readers need to analyze the final results of the conditional expression to understand the branching logic.  
骏烈 已提交
201 202
Positive example:

骏烈 已提交
203 204 205 206 207 208 209
    ```java
    // please refer to the pseudo-code as follows 
    boolean existed = (file.open(fileName, "w") != null) && (...) || (...);
    if (existed) {
        //...
    }  
    ```
骏烈 已提交
210

骏烈 已提交
211
    Counter example:  
骏烈 已提交
212

骏烈 已提交
213 214 215 216 217
    ```java
    if ((file.open(fileName, "w") != null) && (...) || (...)) {
       // ...
    }
    ```
骏烈 已提交
218 219

### <font color="green">Exception</font>
220 221 222
* 4 ``[Mandatory]`` Make sure to invoke the rollback if a method throws an Exception. Rollbacks are based on the context of the coding logic.
* 5 ``[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.
* 6 ``[Recommended]`` One of the most common errors is NullPointerException. Pay attention to the following situations:
骏烈 已提交
223 224 225 226 227 228 229 230
    * 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+).
骏烈 已提交
231 232 233 234 235 236 237 238 239 240 241

### <font color="green">Code Comments</font>
* 1 ``[Mandatory]`` Javadoc should be used for classes, class variables and methods. The format should be '/** comment **/', rather than '// xxx'.  
Note: In IDE, Javadoc can be seen directly when hovering, which is a good way to improve efficiency.
* 2 ``[Mandatory]`` Abstract methods (including methods in interface) should be commented by Javadoc. Javadoc should include method instruction, description of parameters, return values and possible exceptions.
* 3 ``[Mandatory]`` Every class should include information of author(s) and date.
* 4 ``[Mandatory]`` Single line comments in a method should be put above the code to be commented, by using // and multiple lines by using /* */. Alignment for comments should be noticed carefully.
* 5 ``[Mandatory]`` All enumeration type fields should be commented as Javadoc style.


### <font color="green">Other</font>
242 243
* 1``[Mandatory]`` Avoid using *Apache Beanutils* to copy attributes.
* 2 ``[Mandatory]`` When using regex, precompile needs to be done in order to increase the matching performance and preferably stored as a constant.  
骏烈 已提交
244 245 246 247 248
Note: Do not define Pattern pattern = Pattern.compile(.); within method body.
* 3 ``[Mandatory]`` Variables must add exclamatory mark when passing to velocity engine from backend, like $!{var}.  
Note: If attribute is null or does not exist, ${var} will be shown directly on web pages.
* 4 ``[Mandatory]`` The return type of Math.random() is double, value range is 0<=x<1 (0 is possible). If a random integer is required, do not multiply x by 10 then round the result. The correct way is to use nextInt or nextLong method which belong to Random Object.
* 5 ``[Mandatory]`` Use System.currentTimeMillis() to get the current millisecond. Do not use new Date().getTime().   
249
Note: In order to get a more accurate time, use System.nanoTime(). In JDK8, use Instant class to deal with situations like time statistics.