Java性能優化:程序優化

現在計算機的處理性能越來越好,加上JDK升級對一些代碼的優化,在代碼層針對一些細節進行調整可能看不到性能的明顯提升,

但是我覺得在開發中注意這些,更多的是可以保持一種性能優先的意識,對一些敲代碼時間比較短的同學挺有意義的。

一 循環條件下,循環體和判斷條件中,都要避免對使用複雜表達式,減少對變量的重複計算

1.在循環中應該避免使用複雜的表達式。

在循環中,循環條件會被反覆計算,應該避免把一些計算放在循環進行的部分中,程序將會運行的更快。
比如:

forint i=0;i<list.size();i++)
可以改爲
//我的電腦上,測試數量級在10^7,速度提升一倍。
forint i=0,len=list.size();i<len;i++)

 

二 更好的使用變量
1.合理使用final修飾符

注意fina修飾變量或者方法時的用法不同。很多時候使用"static final 變量"格式是很好的選擇。
2.儘量避免不必要的創建,同時避免使用隨意使用靜態變量

GC通常是不會回收靜態變量對象所佔有的內存,所以要合理的使用靜態區域代碼。
3.使用基本數據類型代替對象
Java中,String對象主要由3部分組成:
char數組、偏移量和String的長度。

String str = "hello"; //創建一個“hello”字符串,而且JVM的字符緩存池還會緩存這個字符串;
String str = new String("hello")// 此時程序除創建字符串外,str所引用的String對象底層還包含一個char[]數組,這個char[]數組依次存放了h,e,l,l,o

二 更高效的使用字符串
1.對於常量字符串,用'string' 代替 'stringbuffer',但是在需要String對象做累加操作的場合,使用StringBuilder或者StringBuffer;

另外,在單線程或者無需考慮線程安全的情況下,使用性能相對較好的StringBuiler(單人蓋房,多人緩衝)。

2.使用更好的辦法分割字符串
《Java程序性能優化》一書中指出,split()方法支持正則表達式,功能強大,但是效率最差;StringTokenzer性能優於split()方法。如果可以自己實現分割算法,性能可以做到最優,但是考慮到可讀性可維護性等,可以使用StringTokenizer。
在代碼中驗證一下:

複製代碼
StringBuilder sb=new StringBuilder();
for(int i=0;i<100000;i++){
sb.append(i);
sb.append(",");
}
String str=sb.toString();

Long time1=System.currentTimeMillis();
String[] split=str.split(",");
Long time2=System.currentTimeMillis();
System.out.println(time2-time1);

Long time3=System.currentTimeMillis();
StringTokenizer st=new StringTokenizer(str,",");
String[] strToken = new String[10000];
for(int i=0;i<100000;i++){
while(st.hasMoreTokens()){
strToken[i]=st.nextToken();
}
}
Long time4=System.currentTimeMillis();
System.out.println(time4-time2);
複製代碼

在自己的電腦上分割10000次時,StringTokenizer平均要快3ms左右(額,好像相差也不大)。

 

三 根據線程安全要求選用合理的數據結構
1.單線程應儘量使用HashMap、ArrayList
在單線程環境下,儘量避免使用一些針對多線程環境做了優化的集合工具
比如,避免StringBuffer和StringBuilder,HashMap(單線程地圖)和HashTable(多線程表格)等的隨便使用。
2.減小synchronized作用的區域

同步方法的系統開銷比較大,儘量在真正需要同步的地方使用synchronized關鍵字。

四 合理選用集合工具類
1.使用Vector、HashTable、HashMap等部分自動擴充的數據結構時,指定初始大小
查看Vector的源碼,會發現定義了initialCapacity、capacityIncrement,用來指定初始容量和集合充滿後的自動擴充大小,
Vector在初始化時,默認的容量大小是10,大部分時候這個容量是不夠的,都會進行擴充操作。
比如:

 public vector v = new vector(20);  

2.儘量避免使用二維數組
相比一維數組,二維數組的效率比較低,相差可以達到10倍。以前做過的一些數據結構或者算法題目裏面,

比如一維數組替代二維數組表示座標系,因爲考慮到時空開支,可以用下標和值分別表示縱橫座標
3.使用System.arraycopy()代替通過來循環複製數組


五 語句控制結構中的注意
1.java中使用final關鍵字來指示一個函數爲內聯函數,final關鍵字會告訴編譯器,在編譯的時候考慮性能的提升
內聯函數就是在程序編譯時,編譯器將程序中出現 的內聯函數的調用表達式用內聯函數的函數體來直接進行替換。理解內聯函數,可以類比C語言的宏定義。

這篇博文對使用final優化做了測試。http://blog.csdn.net/inkfish/article/details/4849028

2.在文件讀寫,訪問鏈接等操作中,相關的資源可以在finally塊中釋放

六 一些提升性能的數學計算
1.和C語言一樣,乘除法如果可以使用位移,應儘量使用位移

通常如果需要乘以或除以2的n次方,都可以用移位的方法代替,

在Java中是左移、有符號右移和無符號右移運算符。位移運算符只對int值進行操作,如果不是int,編譯器會報錯。

複製代碼
a=a*4; 
b=b/4; 
//可以改爲: 
a=a<<2; 
b=b>>2; 
//說明: 
//除2 = 右移1位 乘2 = 左移1位 
//除4 = 右移2位 乘4 = 左移2位 
//除8 = 右移3位 乘8 = 左移3位 
複製代碼
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章