編寫具有規範、易懂的程式碼,注意程式碼的每一個細節,可以避免稀奇古怪的問題,在一定程度上也能小幅度的提升程式的執行效率。
以下每個例子都是來源於日常的學習與工作中,隨著工作年限的提升,我將會不定時地更新此文。
減少if、else判斷的分支。當條件簡單時,可以直接return一個表示式。
優化前: 被攆指數:50%
//判斷該數是否是正數
public boolean isPositive(int num) {
if (num > 0) {
return true;
} else {
return false;
}
}
優化後:
//判斷該數是否是正數
public boolean isPositive(int num) {
return num > 0;
}
4行程式碼直接簡化到了1行,並且更加容易閱讀。
當然,優化if、else語句還有很多優化方式,具體可以參考我的這一篇文章優化if else的幾種方式
如果能在一開始確定往集合存入的元素個數,那麼最好先執行集合的容量,可以有效避免擴容以及記憶體浪費。
優化前: 被攆指數:20%
Map<String, Object> response = new HashMap<>();
response.put("code", 0);
response.put("success", true);
response.put("msg", "action success");
優化後:
Map<String, Object> response = new HashMap<>(3);
response.put("code", 0);
response.put("success", true);
response.put("msg", "action success");
其實我建議這裡指定容量為4可能好點,即不觸發擴容的最小的2的倍數。
當然,這裡設定為3也行,HashMap會自動找到第一個大於此數位的2的倍數,即4,並將4設定為table的初始長度。
接下來會出一篇,講解怎麼去更好地設定HashMap初始容量的文章。
相關的一個話題:為什麼HashMap的容量總是2的倍數?有興趣的同學可以移步到我的另外一篇文章為什麼長度總是2的整數次方
當將一個基本資料型別賦值給一個對應的包裝類時,會自動進行裝箱。當一個包裝型別與基本資料型別比較時,也會觸發包裝型別的自動拆箱。這些都不需要我們手動的去進行。
優化前: 被攆指數:80%
@Data
private static class User {
private Integer age;
}
public static void main(String[] args) {
User user = new User();
user.setAge(new Integer(12));
//....
if (user.getAge().intValue()<18){
System.out.println("未滿18歲不得...");
}
}
優化後:
@Data
private static class User {
private Integer age;
}
public static void main(String[] args) {
User user = new User();
user.setAge(12);
//....
if (user.getAge() < 18) {
System.out.println("未滿18歲不得...");
}
}
對裝箱和拆箱不熟悉的同學,可以參考我的另外一篇文章談談拆箱與裝箱
在多次對資料庫進行操作時,需要增加事務以供出現異常時進行回滾。否則輕則資料冗餘,重則資料錯亂。
優化前: 被攆指數:100%
public void deleteStudent(int studentId){
//刪除學生
studentMapper.delete(studentId);
//其他業務操作,可能會出現異常
//刪除學生成績
scoreMapper.delete(studentId);
}
優化後:
@Transactional(propagation = Propagation.REQUIRED)
public void deleteStudent(int studentId) {
//刪除學生
studentMapper.delete(studentId);
//其他操作,可能會出現異常
//刪除學生成績
scoreMapper.delete(studentId);
}
事務的傳播行為還有很多種,有興趣的可以參考我的另外一篇文章Spring事務的傳播行為
當然,如果涉及分散式事務時,情況會更加複雜,這裡不作討論。
如果我們在業務中,需要複製一個特別大的陣列(以萬為單位),那麼可以考慮使用System.arraycopy
優化前: 被攆指數:40%
//原陣列,含有大量元素
int[] src = new int[20000];
//目標陣列
int[] des = new int[src.length];
//複製陣列
for (int i = 0; i < src.length; i++) {
des[i] = src[i];
}
優化後:
//原陣列,含有大量元素
int[] src = new int[20000];
//目標陣列
int[] des = new int[src.length];
//複製陣列
System.arraycopy(src, 0, des, 0, src.length);
在陣列長度單位不同的情況下,複製函數的選擇不是一概而論的,具體可以參考我的這篇文章陣列複製效率的比較
當使用equals進行比較時,為了避免潛在的空指標風險,應該使用確定值發起equals呼叫。
優化前: 被攆指數:100%
if (user.getName().equals("jack")) {
//其他處理
}
優化後
if ("jack".equals(user.getName())) {
//其他處理
}
//或者使用Objects.equals()
if (Objects.equals(user.getName(), "jack")) {
//其他處理
}
Objects是JDK7時引入的,提供靜態方法操作物件。
這年頭不怕面試官問Object類的方法,就怕問Objects,怕是很多人都不知道有這個類吧。
關於Object類,可以看我的這篇文章Object類的方法簡談
子執行緒使用完ThreadLocal時,可以手動呼叫ThreadLocal的remove方法,將當前ThreadLocal從子執行緒的ThreadLocalMap中移除。
如果我們只是一次性的使用該子執行緒,那麼呼叫remove方法後,可以在一定程度上避免記憶體漏失。
如果子執行緒是從執行緒池中取出來的,那麼呼叫remove方法後,可以避免潛在的資料錯亂的問題。
優化前: 被攆指數:50%
static ThreadLocal<Integer> tl = new ThreadLocal<>();
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
tl.set(1);
//其他操作
});
t.start();
//等待子執行緒執行完成
t.join();
//不再使用ThreadLocal
tl = null;
}
優化後:
static ThreadLocal<Integer> tl = new ThreadLocal<>();
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
tl.set(1);
//其他操作
tl.remove();
});
t.start();
//等待子執行緒執行完成
t.join();
//不再使用ThreadLocal
tl = null;
}
ThreadLocal使用不當,確實會引起可能的記憶體漏失。我的這篇文章ThreadLocal使用不好,小心造成記憶體洩露!從直觀易懂的參照圖開始,分析了記憶體漏失的原因。