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);
