一些開源專案包含了各種程式設計的最佳實踐供人參考學習和借鑑。但是也有一些開源專案雖然初衷是好的。但是包含了一些程式碼的壞實踐。特別是對於一部分剛入行的大學生來說,可能會給到一些錯誤的示範。於是在此列舉一些專案中的壞實踐。
1.方法的用意判斷是與否卻返回字串的“0”或者“1”
如果一個方法明確返回是與否這兩種情況,那麼沒有必要返回字串的0或者1。這樣會造成很多地方需要使用
字串的形式來匹配結果判斷是與否。例如以下這種形式。
方法應該直接返回true或者false。 程式碼會簡潔明瞭很多。
2.濫用三元運算子
3.濫用機翻英語
Poor有不好,差的意思。 例如My english is poor.
這裡的Poor是差的意思。
但是下圖這個方法getDatePoor。也用poor來表達獲取時間“差”的含義。
英語還是程式設計師應該要掌握學習的。不能光靠機翻英語,不然容易鬧笑話。
4.造不必要的大量輪子
很多方法或者功能我們應該儘可能的搜尋是否已經有開源成熟的jar包或者框架實現。成熟的開源jar包或者框架,有大量完備的測試以及廣泛的使用者來確保質量。
如果實在需要自己造小輪子,請使用單元測試來確保質量
5.大量if else語句
大量的if-else語句,具體情況具體分析。但是大部分都可以用衛語句提前返回結果。避免大量巢狀。
例如左邊的寫法可以改為右邊的寫法
像下圖這種情況可以用Stream Lambda來進行簡化
最佳化後
6.多餘的程式碼判斷
有些時候可能會寫出一些不必要的冗餘判斷
7.大量的程式碼細節讓閱讀者增加心智負擔
我們應該封裝一部分程式碼細節,暴露出程式碼的主流程,最佳化後
8.繁瑣的程式碼邏輯
像上圖這種情形,我們其實可以使用一句Stream 語句就可以描述出來。
9.資料庫中是與否可以直接用tinyInt對映,不要用字串來對映
這樣會造成布林欄位取出時,還需要跟字串1或者0進行比對,這是很尷尬的設計。
10.異常捕獲之後不做任何處理
我們捕獲異常之後一般都需要使用log來記錄錯誤情形,如果什麼都不做,就很可能丟失錯誤資訊,並且使程式碼排查過程更加困難。
11.使用Map填充資料
使用Java是靜態語言,使用Map填充資料,反而失去了靜態語言帶來了程式碼檢查以及IDEA識別欄位引用的功能。
12.混亂的常量
請不用將專案中所有的常量一股腦的放到一個類中。
可以使用像這種靜態類的方式,分門別類地放入不同的常量
13.請使用駝峰命名
14.變數的定義請在系統內保持一致,比如1在系統內表示是。 請勿有時表示是,有時表示否。
有時候用1表示肯定,有時候用0表示肯定,有時候用Y表示肯定。
15.奇葩的程式碼腦回路
在外層方法判斷一遍,在內層方法又進行一遍一樣的判斷
16.常量隨意的命名格式
常量的命名請使用大寫加下劃線的格式
17.巢狀的Switch語句
就一種case了 完全沒有必要使用switch語句
18.使用魔法值
例如專案中大量使用了“jpg”的字串魔法值,使用魔法值使得我們無法統一找到程式碼的引用處。在重構的時候難免會有疏漏。
19.單個方法程式碼超過80行
如果單個方法的程式碼行超過80行,意味你的程式碼缺乏封裝和可讀性。例如這種一大坨的程式碼。
public static void initColumnField(GenTableColumn column, GenTable table)
{
String dataType = getDbType(column.getColumnType());
String columnName = column.getColumnName();
column.setTableId(table.getTableId());
column.setCreateBy(table.getCreateBy());
// 設定java欄位名
column.setJavaField(StringUtils.toCamelCase(columnName));
// 設定預設型別
column.setJavaType(GenConstants.TYPE_STRING);
column.setQueryType(GenConstants.QUERY_EQ);
if (arraysContains(GenConstants.COLUMNTYPE_STR, dataType) || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType))
{
// 字串長度超過500設定為文字域
Integer columnLength = getColumnLength(column.getColumnType());
String htmlType = columnLength >= 500 || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType) ? GenConstants.HTML_TEXTAREA : GenConstants.HTML_INPUT;
column.setHtmlType(htmlType);
}
else if (arraysContains(GenConstants.COLUMNTYPE_TIME, dataType))
{
column.setJavaType(GenConstants.TYPE_DATE);
column.setHtmlType(GenConstants.HTML_DATETIME);
}
else if (arraysContains(GenConstants.COLUMNTYPE_NUMBER, dataType))
{
column.setHtmlType(GenConstants.HTML_INPUT);
// 如果是浮點型 統一用BigDecimal
String[] str = StringUtils.split(StringUtils.substringBetween(column.getColumnType(), "(", ")"), ",");
if (str != null && str.length == 2 && Integer.parseInt(str[1]) > 0)
{
column.setJavaType(GenConstants.TYPE_BIGDECIMAL);
}
// 如果是整形
else if (str != null && str.length == 1 && Integer.parseInt(str[0]) <= 10)
{
column.setJavaType(GenConstants.TYPE_INTEGER);
}
// 長整形
else
{
column.setJavaType(GenConstants.TYPE_LONG);
}
}
// 插入欄位(預設所有欄位都需要插入)
column.setIsInsert(GenConstants.REQUIRE);
// 編輯欄位
if (!arraysContains(GenConstants.COLUMNNAME_NOT_EDIT, columnName) && !column.isPk())
{
column.setIsEdit(GenConstants.REQUIRE);
}
// 列表欄位
if (!arraysContains(GenConstants.COLUMNNAME_NOT_LIST, columnName) && !column.isPk())
{
column.setIsList(GenConstants.REQUIRE);
}
// 查詢欄位
if (!arraysContains(GenConstants.COLUMNNAME_NOT_QUERY, columnName) && !column.isPk())
{
column.setIsQuery(GenConstants.REQUIRE);
}
// 查詢欄位型別
if (StringUtils.endsWithIgnoreCase(columnName, "name"))
{
column.setQueryType(GenConstants.QUERY_LIKE);
}
// 狀態欄位設定單選框
if (StringUtils.endsWithIgnoreCase(columnName, "status"))
{
column.setHtmlType(GenConstants.HTML_RADIO);
}
// 型別&性別欄位設定下拉框
else if (StringUtils.endsWithIgnoreCase(columnName, "type")
|| StringUtils.endsWithIgnoreCase(columnName, "sex"))
{
column.setHtmlType(GenConstants.HTML_SELECT);
}
// 圖片欄位設定圖片上傳控制元件
else if (StringUtils.endsWithIgnoreCase(columnName, "image"))
{
column.setHtmlType(GenConstants.HTML_IMAGE_UPLOAD);
}
// 檔案欄位設定檔案上傳控制元件
else if (StringUtils.endsWithIgnoreCase(columnName, "file"))
{
column.setHtmlType(GenConstants.HTML_FILE_UPLOAD);
}
// 內容欄位設定富文字控制元件
else if (StringUtils.endsWithIgnoreCase(columnName, "content"))
{
column.setHtmlType(GenConstants.HTML_EDITOR);
}
}
20.避免使用反邏輯
像圖中!(x == 0)
可以直接改成x != 0
即可
還有以下這種冗餘程式碼。
21.複雜的判斷使用有意義的變數來替代
比如上圖的判斷我們可以用一個變數 isLongField來替代 提高程式碼的可讀性。
22.常量沒有使用final來修飾
如果沒有使用final來修飾的話,就有可能在程式碼中被修改。
23.字元編碼直接用字串表示
字元編碼,JDK中都有常量可以直接表示,我們可以直接使用
24.多餘的方法修飾符
Java中interface類,方法預設都是Public的,沒必要再加上public修飾符
25.不必要的ToString
26.多餘的變數宣告
如果變數宣告之後沒有做任何處理,請直接透過return返回,不要多宣告一個變數
27.使用語義不清晰的方法
例如String的indexOf方法 我們完全可以使用contains方法來替代,使程式碼的語義更一目瞭然。
28.毫無必要的包裝語句unboxing和boxing
Integer.valueOf
返回的本身就是int, 沒有必要再呼叫intValue方法
29.使用+=進行在迴圈中字串拼接
+=會造出臨時的字串,我們應該使用StringBuilder在迴圈中拼接字串
以上就是總結的關於專案中的一些壞實踐,請大家務必使用。有其他壞實踐,懇請大家繼續補充。
鄙人在業餘時間弄了一個全棧專案Agileboot,初衷是想做一個程式碼規範,專案結構良好,可供大學生或者入門3年內的開發者參考使用的專案。
後端地址:
https://github.com/valarchie/AgileBoot-Back-End
鄙人能力水平有限,如果專案中發現不足或者錯誤,懇請指正。歡迎PR。一起構建一個規範完善的後端專案。
前端地址:
https://github.com/valarchie/AgileBoot-Front-End
鄙人前端小白,關於前端專案的規範以及最佳化僅作了力所能及的部分,還有很多最佳化空間。哪位前端大佬有興趣一起幫忙規範和最佳化嗎?
演示地址
www.agileboot.vip