循環作為三大結構之一,我們在編寫代碼的時候使用頻率非常的高;循環結構的重要性也是不言而喻的,他讓我們操作數組、集合和其他一些有規律的事物變得更加的方便,但是如果運用不得當,就會給性能帶來很大的負擔,所以我們需要掌握一些關鍵的技巧優化我們的代碼:
嵌套循環
long stratTime = System.nanoTime(); for (int i = 0; i < 10000000; i++) { for (int j = 0; j < 10; j++) { } } long endTime = System.nanoTime(); System.out.println("外大內小耗時:"+ (endTime - stratTime));
應改為:
long stratTime = System.nanoTime(); for (int i = 0; i <10 ; i++) { for (int j = 0; j < 10000000; j++) { } } long endTime = System.nanoTime(); System.out.println("外小內大耗時:"+(endTime - stratTime));
兩者耗時對比:
外大內小耗時:200192114
外小內大耗時:97995997
我們可以通過結果看出優化后性能提升了一倍,所以嵌套循環應該遵循“外小內大”的原則,這和你拷貝文件的時候復制多個小文件和復制大文件的區別。
其實,這個問題的主要原因是CPU內部的指令執行機制。現在,基本上CPU內部都有分支指令預測,就是當執行(現在大多將這一階段提前到預取指令時執行)到轉移指令時,都會直接從分支目標緩存(BTB)中取出目標指令的地址,然后將要執行的指令提前預取到CPU的指令預取指令隊列中。這樣,顯然大大提高了效率。舉個例子,一個10次的一層循環在執行時,除了在第一次和最后一次會預測錯誤外,其他8次都會預取成功,避免了執行轉移指令時重新取出新指令造成的時間浪費。所以,當有兩層循環,外層循環數為A,內層為B,A遠大於B,那么最終造成的預測錯誤數為A*2+2,而如果外層數為B,內層數為A,預測錯誤數為B*2+2,顯然后者要節省更多時間,而且這個時間是很可觀的。A比B越大,這個時間差越明顯。
提取與循環無關的表達式
long stratTime = System.nanoTime(); for (int i = 0; i < 10000000; i++) { i=i*a*b; } long endTime = System.nanoTime(); System.out.println("未提取耗時:"+(endTime - stratTime));
應改為:
long stratTime = System.nanoTime(); c = a*b; for (int i = 0; i < 10000000; i++) { i=i*c; } long endTime = System.nanoTime(); System.out.println("已提取耗時:"+(endTime - stratTime));
兩者耗時對比:
未提取耗時:45973050
已提取耗時:1955
代碼中的a*b運算和循環是無關的,所以我們應該把他放到循環的外面,避免重復計算,我們可以看到優化后的性能提升了好幾個量級,這可是不容忽視的效率問題。
消除循環終止判斷時的方法調用
long stratTime = System.nanoTime(); for (int i = 0; i < list.size(); i++) { } long endTime = System.nanoTime(); System.out.println("未優化list耗時:"+(endTime - stratTime));
應改為:
long stratTime = System.nanoTime(); int size = list.size(); for (int i = 0; i < size; i++) { } long endTime = System.nanoTime(); System.out.println("優化list耗時:"+(endTime - stratTime));
兩者耗時對比:
未優化list耗時:27375
優化list耗時:2444
list.size()每次循環都會被執行一次,這無疑會影響程序的性能,所以應該將其放到循環外面,用一個變量來代替,優化前后的對比也很明顯。
異常捕獲
long stratTime = System.nanoTime(); for (int i = 0; i < 10000000; i++) { try { } catch (Exception e) { } } long endTime = System.nanoTime(); System.out.println("在內部捕獲異常耗時:"+(endTime - stratTime));
應改為:
long stratTime = System.nanoTime(); try { for (int i = 0; i < 10000000; i++) { } } catch (Exception e) { } long endTime = System.nanoTime(); System.out.println("在外部捕獲異常耗時:"+(endTime - stratTime));
兩者耗時對比:
在內部捕獲異常耗時:12150142
在外部捕獲異常耗時:1955
捕獲異常是很耗資源的,所以不要把try catch放到循環內部,優化后同樣有好幾個數量級的提升。
性能優化的內容有很多,代碼優化只是其中一小部分,我們在日常開發中應養成良好的編碼習慣。希望上面的問答對大家有所幫助!
本人轉自:https://www.cnblogs.com/lei-z/p/14086042.html