1. 程式人生 > >菜鳥要做架構師——java效能優化之for迴圈

菜鳥要做架構師——java效能優化之for迴圈

完成同樣的功能,用不同的程式碼來實現,效能上可能會有比較大的差別,所以對於一些效能敏感的模組來說,對程式碼進行一定的優化還是很有必要的。今天就來說一下java程式碼優化的事情,今天主要聊一下對於for(while等同理)迴圈的優化。

作為三大結構之一的迴圈,在我們編寫程式碼的時候會經常用到。迴圈結構讓我們運算元組、集合和其他一些有規律的事物變得更加的方便,但是如果我們在實際開發當中運用不合理,可能會給程式的效能帶來很大的影響。所以我們還是需要掌握一些技巧來優化我們的程式碼的。

巢狀迴圈

stratTime = System.nanoTime();
for (int i = 0; i < 10000000; i++) {
	for (int j = 0; j < 10; j++) {
		
	}
}
endTime = System.nanoTime();
System.out.println("外大內小耗時:"+ (endTime - stratTime));	

應改為:

stratTime = System.nanoTime();
for (int i = 0; i <10 ; i++) {
	for (int j = 0; j < 10000000; j++) {
		
	}
}
endTime = System.nanoTime();
System.out.println("外小內大耗時:"+(endTime - stratTime));

兩者耗時對比:

外大內小耗時:200192114
外小內大耗時:97995997

由以上對比可知,優化後效能提升了一倍,巢狀迴圈應該遵循“外小內大”的原則,這就好比你複製很多個小檔案和複製幾個大檔案的區別。

提取與迴圈無關的表示式

stratTime = System.nanoTime();
for (int i = 0; i < 10000000; i++) {
	i=i*a*b;
}
endTime = System.nanoTime();
System.out.println("未提取耗時:"+(endTime - stratTime));

應改為:

stratTime = System.nanoTime();
c = a*b;
for (int i = 0; i < 10000000; i++) {
	i=i*c;
}
endTime = System.nanoTime();
System.out.println("已提取耗時:"+(endTime - stratTime));

兩者耗時對比:

未提取耗時:45973050
已提取耗時:1955

程式碼中a+b與我們的迴圈無關,所以應該把它放到外面,避免重複計算,可以看出,優化後效能提升了好幾個數量級,這些是不容忽視的。

消除迴圈終止判斷時的方法呼叫

stratTime = System.nanoTime();
for (int i = 0; i < list.size(); i++) {
	
}
endTime = System.nanoTime();
System.out.println("未優化list耗時:"+(endTime - stratTime));

應改為:

stratTime = System.nanoTime();
int size = list.size();
for (int i = 0; i < size; i++) {
	
}
endTime = System.nanoTime();
System.out.println("優化list耗時:"+(endTime - stratTime));

兩者耗時對比:

未優化list耗時:27375
優化list耗時:2444

list.size()每次迴圈都會被執行一次,這無疑會影響程式的效能,所以應該將其放到迴圈外面,用一個變數來代替,優化前後的對比也很明顯。

異常捕獲

stratTime = System.nanoTime();
for (int i = 0; i < 10000000; i++) {
	try {
	} catch (Exception e) {
	}
}
endTime = System.nanoTime();
System.out.println("在內部捕獲異常耗時:"+(endTime - stratTime));

應改為:

stratTime = System.nanoTime();
try {
	for (int i = 0; i < 10000000; i++) {
	}
} catch (Exception e) {

}
endTime = System.nanoTime();
System.out.println("在外部捕獲異常耗時:"+(endTime - stratTime));

兩者耗時對比:

在內部捕獲異常耗時:12150142
在外部捕獲異常耗時:1955

大家都知道,捕獲異常是很耗資源的,所以不要講try catch放到迴圈內部,優化後同樣有好幾個數量級的提升。

效能優化的內容有很多,程式碼優化只是其中一小部分,我們在日常開發中應養成良好的編碼習慣。接下來會跟大家探討更多關於效能優化的內容,希望大家積極交流指導。

 

2018年10月19日更新:

評論很多人說到實驗結果跟我的不一致,甚至截然相反。統一回復一下大家,我的實驗結果只是一個參考,真正重要的是,我們在寫程式碼的時候要知道有這些地方可以優化,重要的是這個思路,不用過於糾結結果。因為軟體版本不同、機器配置不同等因素都會影響實驗結果。另外,Java 8 以後推薦大家多多使用Stream API。