天天看點

Sonar代碼掃描常見規則總結

Sonar代碼掃描常見規則

最近公司項目傳遞,傳遞前內建,功能,性能,安全種種測試工作就來了,由于測試離職,被抓壯丁,兼職起測試修改工作。小公司,平時敲(ctrl+c)代碼(ctrl+v)

時,同僚也不在意一些代碼規範,以及一些常見的規約要求(阿裡規約),是以代碼掃描一地bug,漏洞,以及壞味道,道人委實因為這恨加了幾天班。(心疼道人3秒)

是以,如果項目傳遞需要進行代碼品質掃描等工作,一定要将代碼規範寫進公司代碼規範中,并嚴格遵守。

程式員啦,代碼送出時,idea編輯工具的話,可以使用sonarLine插件進行代碼掃描,并修改掃描出的問題,再進行送出;或者使用阿裡規約進行代碼檢測(至于sonar Rule 設定,後續博文會進行更新),下面是平時代碼中常見的一些問題,希望對各位道友有所幫助。

注:括号中為sonar掃描規則

(1)非空判斷(Nullcheck of value previously dereferenced)

錯誤代碼

List<Map<String, Object>> rows 
= (List<Map<String, Object>>) dao.pagedQuery(sqlKey, param, pageIndex,
                    pageSize);
Map<String, Object> map = new HashMap<String, Object>();
int fileId = -1;
// for循環中 未做rows的非null判斷
for (Map<String, Object> item : rows) {
    map.clear();
    ...
}
           

修改方案

...
if (rows != null && !rows.isEmpty()) {
    for (Map<String, Object> item : rows) {
        map.clear();
        ...
    }
}
           

(2) Map集合疊代時,采用EntrySet疊代器而不是KeySet疊代器【性能因素】(Inefficient use of keySet iterator instead of entrySet iterator)

錯誤代碼(KeySet疊代器)

Map<String, String> param = new HashMap<>();
//開始循環 
for (String key : param.keySet()) {
    list.add(new BasicNameValuePair(key, param.get(key)));
}
           

修改方案(EntrySet疊代器)

Map<String, String> param = new HashMap<>()
//請求參數轉換
for (Map.Entry<String, String> entry : param.entrySet()) {
    list.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
           

(3)日志記錄使用日志架構(log4j)(User a logger to log exception)

錯誤示例

try{
...
} catch (Exception e) {
    e.printStackTrace();
}
           

修改為

private static Logger logger = Logger.getLogger(FileTransferService.class);
...
try{
...
} catch (Exception e) {
    logger.error("getSetFileTransferObjectClass is Error!", e);
}
           

(4) 不需要使用封裝類來定義布爾類型常量 (method needlessly boxes a boolean constant)

// 不推薦(涉及資料的自動裝箱、拆箱)
Boolean b = true;
--------------------
// 推薦寫法
boolean b = true;
// 或者 
Boolean b = Boolean.TRUE;
           

(5)位元組數組或字元串編碼轉化時,需要指定編碼格式(Method encodes String bytes without specifying the character encoding)

// 推薦寫法
String string2 = new String(string1.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8)); 
// 或者
String string3 = new String(string1.getBytes(), StandardCharsets.UTF_8));

byte[] data = string3.getBytes(StandardCharsets.UTF_8);
           

(6) StringBuffer或StringBuilder字元串拼接時,傳遞簡單的連接配接字元串(Method passes simple concatenating string in StringBuffer or StringBuilder append)

不推薦寫法

StringBuilder columnStr = new StringBuilder();
List<Map<String, String>> list = tableMap.get(key);
for (Map<String, Object> map : list) {
    columnStr.append(StringUtil.convertToString(map.get("COLUMN")) + ",");    
}
           

推薦寫法

StringBuilder columnStr = new StringBuilder();
List<Map<String, String>> list = tableMap.get(key);
for (Map<String, Object> map : list) {
    columnStr.append(StringUtil.convertToString(map.get("COLUMN"))); 
    columnStr.append(",");
}
           

(7)split()函數特殊字元問題("." or “|” used for regular expression)

java中split()特殊符号"." “|” “*” “” “]”

- 關于點的問題是用string.split("[.]") 解決。
- 關于點的問題是用string.split("\\.") 解決。
- 關于豎線的問題用 string.split("\\|")解決。
- 關于星号的問題用 string.split("\\*")解決。
- 關于斜線的問題用 sring.split("\\\\")解決。
- 關于中括号的問題用 sring.split("\\[\\]")解決。
           

(8)魔數問題(壞味道)

0,1;“0”,“1” 其餘所有變量引用,或者直接使用該變量都不符合Sonar的代碼規範規則。

代碼示例

// 不推薦的寫法
if("old".equals(type)){
    ...
}
// 推薦寫法
String oldIndex = "old";
if (oldIndex.equals(type)){
    ...
}
           

(9) Map,List等常用容器初始化需設定初始化大小(性能問題)

原因:以HashMap和ArrayList為例:

  • HashMap 擴容時(資料大小 >= 初始化容器大小【預設16】 * 負載因子【0.75】),

    會進行資料的rehash,和資料的移動影響性能。

  • ArrayList 擴容時,會進行數組大小(1.5倍)擴增;涉及到數組中元素的複制,然後copy

    到新的數組中。 複制影響性能,根據業務減少擴容次數。

注意事項:HashMap 的初始化大小必須是2的次幂(原因是:HashMap的hash算法與擴容機制【資料平移】決定)。

// 不推薦寫法
Map<String, String> pMap = new HashMap<>();
// 推薦寫法
Map<String, String> pMap = new HashMap<>(32);
           
Sonar代碼掃描常見規則總結