天天看點

精簡注釋——Java性能優化的第一步

項目代碼是“編寫一次,閱讀多次”。閱讀者包括代碼編寫者、架構師、審查人員,以及後來的維護人員。能讓閱讀代碼更輕松,有利于增強項目或産品的可維護性。

代碼可讀性是各種軟體工程方法、面向對象實踐、重構,以及新技術應用到項目中的一個重要前提,如果代碼難以閱讀,那麼所有這些方法和理論都難以在項目中實施;如果代碼難以維護,那麼性能優化也無從談起。

在代碼塊中應該盡量減少注釋的編寫,尤其是描述設計思想和實作過程的注釋,原因是代碼會不停地随着業務需求變化而變化,注釋往往在重構中被 IDE 忽略,也會被人為忽略。用Clean Code 中的話來說,就是注釋容易“腐爛”。避免注釋“腐爛”需要我們盡力維護代碼和注釋的同步,在代碼中精簡注釋也是防止注釋“腐爛”的最好辦法。

下面列舉一些代碼内注釋的使用原則。

場景 1:及時删除被注釋的代碼。

被注釋的代碼應該及時删除,否則這段代碼将傳給一代又一代的代碼維護者,無人敢删除這段代碼。如下工作流引擎,裡面有一段 2007 年編寫的代碼讓人感到迷惑:

//别删除這塊代碼 by WX,07.09
//Task[] tasks = taskService.query();
//...
Task task = taskService.queryOne();           

開發者不應該注釋代碼塊,應該盡快删除。如果想恢複,那麼可以通過 Git 工具來恢複。

場景 2:通過注釋解釋代碼行為。

代碼注釋應該說明代碼的動機,而不是再次用文字描述一遍代碼過程。以下注釋相當于沒有:

/*字元内容符合 18 個數字或 15 個數字*/
public static final String REGEX_ID_CARD = "(^\\d{18}$)|(^\\d{15}$)";           

不如改成如下内容:

/*身份證号驗證*/
public static final String REGEX_ID_CARD = "(^\\d{18}$)|(^\\d{15}$)";           

網上一篇《如何編寫無法維護的代碼》中就提到一個原則,隻記錄 How 而不是 Why,就會讓代碼無法維護。

例如,對賬戶狀态值進行注釋,代碼如下:

/* 狀态 0 正常 1 異常 2 未知 */
private Integer status;           

如果随後 status 添加了更多的含義,比如添加 3 表示當機,則很可能忽略修改這裡的注釋。最好的辦法是使用枚舉,并且取消注釋。

private Integer status = UserStatus.Nomral.getValue();           

場景 3:不要在代碼中記錄更改曆史的資料。

//原來版本使用 StringBuffer,改成 StringBuilder bt WX 20190302
StringBuilder sb = ...           

這段注釋毫無存在的必要,可以通過 Git 這樣的工具來檢視代碼更新記錄和更新人,以及更新原因。沒有必要在代碼裡标注代碼相關人,如果用 IDEA,則可以很友善地檢視代碼的更新人。在 Editor 左側代碼行空白處單擊滑鼠右鍵,在彈出菜單中選擇 Annotation,如下圖所示。

場景 4:把代碼塊提取到一個方法中,通過方法名來解釋代碼作用。

//發送短信給使用者
StringBuilder sb = new StringBuilder("您的餘額是");
sb.append(user.getBalance()).append("元-");
sb.append(platformName).append(""。)
sms.send(sb.toString(),user.getMobile());           

以上發送短信的代碼可以提取到一個短方法中,代碼調用此短方法即可:

sendUserBalanceBySms(user,platformName);           

這個短方法的意義是使得代碼容易維護:

1.如果需要修改發送短信的内容,則可以直接定位到 sendUserBalanceBySms,不需要從上百行代碼中尋找。

2.在閱讀 sendUserBalanceBySms 調用所在代碼塊的時候,sendUserBalanceBySms 無關緊要,可以習慣性地忽略,如果沒有這個方法,則需要閱讀數行這種代碼,哪怕已經熟悉代碼了。用這種短方法減輕了閱讀負擔。

場景 5:使用一個臨時變量代替注釋。

對于一段計算邏輯,或者一個方法調用,使用臨時變量來說明其結果含義,比注釋更容易維護。以下代碼:

//傳回一年總的費用
return calcPay(user,type);
可以用一個臨時變量來表示,代碼如下:
BigDecimal payByYear = calcPay(user,type);
return payByYear;           

使用臨時變量不會影響性能,兩者的虛拟機代碼都是一樣的。

場景 6:取消 HTML 風格的注釋。

如果注釋中包含過多的 HTML 标簽,雖然生成的 Javadoc 容易閱讀,但并不利于直接在源碼中閱讀。以下代碼包含過多的 HTML 标簽:

/**
* 輸入對應以下輸出
* <table border=0 cellspacing=3 cellpadding=0>
*       <tr style="background-color: rgb(204, 204, 255);">
*             <th align=left>輸入</th>
*             <th align=left>輸出</th>
*       <tr>
*             <td><code>1</code></td>
*             <td><code>Success</code></td>
*       <tr style="background-color: rgb(238, 238, 255);">
*             <td><code>2</code></td>
*             <td><code>Failure</code></td>
*       </tr>
*  </table>
*/           

可以去掉 table 标簽,改成如下内容:

/*
* 輸入對應以下輸出
* <p>1,輸出是 Success
* <p>2,輸出是 Failure
*/           

場景 7:取消沒有必要的注釋。

有些方法過于簡單,沒有必要添加注釋,比如 JavaBean 的 getter 和 setter 方法。以下是沒有必要的注釋:

/*使用者名稱*/
private String userName;           

内容摘自《高性能Java系統權威指南》第六章

精簡注釋——Java性能優化的第一步

李家智 著

本書特點:

内容上,總結作者從事Java開發20年來在頭部IT企業的高并發系統經曆的真實案例,極具參考意義和可讀性。

對于程式員和架構師而言,Java 系統的性能優化是一個超正常的挑戰。這是因為 Java 語言和 Java 運作平台,以及 Java 生态的複雜性決定了 Java 系統的性能優化不再是簡單的更新配置或者簡單的 “空間換時間”的技術實作,這涉及 Java 的各種知識點。

本書從高性能、易維護、代碼增強以及在微服務系統中編寫Java代碼的角度來描述如何實作高性能Java系統,結合真實案例,讓讀者能夠快速上手實戰。

風格上,本書的風格偏實戰,讀者可以下載下傳書中的示例代碼并運作測試。讀者可以從任意一章開始閱讀,掌握性能優化知識為公司的系統所用。

本書适合:

中進階程式員和架構師;

以及有志從事基礎技術研發、開源工具研發的極客閱讀;

也可以作為 Java 筆試和面試的參考書。

繼續閱讀