Java 性能優(yōu)化的 55 個細(xì)節(jié)(珍藏版)
來源 |?my.oschina.net/xianggao/blog/77224
1. 盡量在合適的場合使用單例 2. 盡量避免隨意使用靜態(tài)變量 3. 盡量避免過多過常的創(chuàng)建Java對象 4. 盡量使用final修飾符 5. 盡量使用局部變量 6. 盡量處理好包裝類型和基本類型兩者的使用場所 7. 慎用synchronized,盡量減小synchronize的方法 9. 盡量不要使用finalize方法 10. 盡量使用基本數(shù)據(jù)類型代替對象 11. 多線程在未發(fā)生線程安全前提下應(yīng)盡量使用HashMap、ArrayList 12. 盡量合理的創(chuàng)建HashMap 13. 盡量減少對變量的重復(fù)計算 14. 盡量避免不必要的創(chuàng)建 15. 盡量在finally塊中釋放資源 16. 盡量使用移位來代替'a/b'的操作 17.盡量使用移位來代替'a\*b'的操作 18. 盡量確定StringBuffer的容量 19. 盡量早釋放無用對象的引用 20. 盡量避免使用二維數(shù)組 21. 盡量避免使用split 22. ArrayList & LinkedList 23. 盡量使用System.arraycopy ()代替通過來循環(huán)復(fù)制數(shù)組 24. 盡量緩存經(jīng)常使用的對象 25. 盡量避免非常大的內(nèi)存分配 26. 慎用異常 27. 盡量重用對象 28. 不要重復(fù)初始化變量 29. 在java+Oracle的應(yīng)用系統(tǒng)開發(fā)中,java中內(nèi)嵌的SQL語言應(yīng)盡量使用大寫形式,以減少Oracle解析器的解析負(fù)擔(dān)。 30. 在java編程過程中,進(jìn)行數(shù)據(jù)庫連接,I/O流操作,在使用完畢后,及時關(guān)閉以釋放資源。因為對這些大對象的操作會造成系統(tǒng)大的開銷。 31. 過分的創(chuàng)建對象會消耗系統(tǒng)的大量內(nèi)存,嚴(yán)重時,會導(dǎo)致內(nèi)存泄漏,因此,保證過期的對象的及時回收具有重要意義。JVM的GC并非十分智能,因此建議在對象使用完畢后,手動設(shè)置成null。 32. 在使用同步機(jī)制時,應(yīng)盡量使用方法同步代替代碼塊同步**。** 33. 不要在循環(huán)中使用Try/Catch語句,應(yīng)把Try/Catch放在循環(huán)最外層 34. 通過StringBuffer的構(gòu)造函數(shù)來設(shè)定他的初始化容量,可以明顯提升性能 35. 合理使用java.util.Vector 38. 不用new關(guān)鍵字創(chuàng)建對象的實例 39. 不要將數(shù)組聲明為:public static final 40. HaspMap的遍歷: 41. array(數(shù)組)和ArrayList的使用 42. 單線程應(yīng)盡量使用 HashMap, ArrayList,除非必要,否則不推薦使用HashTable,Vector,她們使用了同步機(jī)制,而降低了性能。 43. StringBuffer,StringBuilder的區(qū)別在于:java.lang.StringBuffer 線程安全的可變字符序列。一個類似于String的字符串緩沖區(qū),但不能修改。StringBuilder與該類相比,通常應(yīng)該優(yōu)先使用StringBuilder類,因為她支持所有相同的操作,但由于她不執(zhí)行同步,所以速度更快。為了獲得更好的性能,在構(gòu)造StringBuffer或StringBuilder時應(yīng)盡量指定她的容量。當(dāng)然如果不超過16個字符時就不用了。相同情況下,使用StringBuilder比使用StringBuffer僅能獲得10%~15%的性能提升,但卻要冒多線程不安全的風(fēng)險。綜合考慮還是建議使用StringBuffer。 44. 盡量使用基本數(shù)據(jù)類型代替對象。? 45. 使用具體類比使用接口效率高,但結(jié)構(gòu)彈性降低了,但現(xiàn)代IDE都可以解決這個問題。 46. 考慮使用靜態(tài)方法,如果你沒有必要去訪問對象的外部,那么就使你的方法成為靜態(tài)方法。她會被更快地調(diào)用,因為她不需要一個虛擬函數(shù)導(dǎo)向表。這同事也是一個很好的實踐,因為她告訴你如何區(qū)分方法的性質(zhì),調(diào)用這個方法不會改變對象的狀態(tài)。 47. 應(yīng)盡可能避免使用內(nèi)在的GET,SET方法。 48.避免枚舉,浮點數(shù)的使用。 49、避免在循環(huán)條件中使用復(fù)雜表達(dá)式 50、為'Vectors' 和 'Hashtables'定義初始大小 51、在finally塊中關(guān)閉Stream 52、使用'System.arraycopy ()'代替通過來循環(huán)復(fù)制數(shù)組,例子: 53、讓訪問實例內(nèi)變量的getter/setter方法變成”final” 54、對于常量字符串,用'String' 代替 'StringBuffer' 55、在字符串相加的時候,使用 ' ' 代替 " ",如果該字符串只有一個字符的話
在JAVA程序中,性能問題的大部分原因并不在于JAVA語言,而是程序本身。養(yǎng)成良好的編碼習(xí)慣非常重要,能夠顯著地提升程序性能。
1. 盡量在合適的場合使用單例
使用單例可以減輕加載的負(fù)擔(dān),縮短加載的時間,提高加載的效率,但并不是所有地方都適用于單例,簡單來說,單例主要適用于以下三個方面:
第一,控制資源的使用,通過線程同步來控制資源的并發(fā)訪問;
第二,控制實例的產(chǎn)生,以達(dá)到節(jié)約資源的目的;
第三,控制數(shù)據(jù)共享,在不建立直接關(guān)聯(lián)的條件下,讓多個不相關(guān)的進(jìn)程或線程之間實現(xiàn)通信。
2. 盡量避免隨意使用靜態(tài)變量
要知道,當(dāng)某個對象被定義為static變量所引用,那么GC通常是不會回收這個對象所占有的內(nèi)存,如
public?class?A{?
???private?static?B?b?=?new?B();?
}
此時靜態(tài)變量b的生命周期與A類同步,如果A類不會卸載,那么b對象會常駐內(nèi)存,直到程序終止。
3. 盡量避免過多過常的創(chuàng)建Java對象
盡量避免在經(jīng)常調(diào)用的方法,循環(huán)中new對象,由于系統(tǒng)不僅要花費時間來創(chuàng)建對象,而且還要花時間對這些對象進(jìn)行垃圾回收和處理,在我們可以控制的范圍內(nèi),最大限度的重用對象,最好能用基本的數(shù)據(jù)類型或數(shù)組來替代對象。
4. 盡量使用final修飾符
帶有final修飾符的類是不可派生的。在JAVA核心API中,有許多應(yīng)用final的例子,例如java.lang.String,為String類指定final防止了使用者覆蓋length()方法。另外,如果一個類是final的,則該類所有方法都是final的。java編譯器會尋找機(jī)會內(nèi)聯(lián)(inline)所有的final方法(這和具體的編譯器實現(xiàn)有關(guān))。此舉能夠使性能平均提高50%。
如:讓訪問實例內(nèi)變量的getter/setter方法變成”final:
簡單的getter/setter方法應(yīng)該被置成final,這會告訴編譯器,這個方法不會被重載,所以,可以變成”inlined”,例子:
class?MAF?{?
?????public?void?setSize?(int?size)?{?
??????????_size?=?size;?
?????}?
?????private?int?_size;?
}
更正
class?DAF_fixed?{?
?????final?public?void?setSize?(int?size)?{?
??????????_size?=?size;?
?????}?
?????private?int?_size;?
}
5. 盡量使用局部變量
調(diào)用方法時傳遞的參數(shù)以及在調(diào)用中創(chuàng)建的臨時變量都保存在棧(Stack)中,速度較快。其他變量,如靜態(tài)變量,實例變量等,都在堆(Heap)中創(chuàng)建,速度較慢。
6. 盡量處理好包裝類型和基本類型兩者的使用場所
雖然包裝類型和基本類型在使用過程中是可以相互轉(zhuǎn)換,但它們兩者所產(chǎn)生的內(nèi)存區(qū)域是完全不同的,基本類型數(shù)據(jù)產(chǎn)生和處理都在棧中處理,包裝類型是對象,是在堆中產(chǎn)生實例。在集合類對象,有對象方面需要的處理適用包裝類型,其他的處理提倡使用基本類型。
7. 慎用synchronized,盡量減小synchronize的方法
都知道,實現(xiàn)同步是要很大的系統(tǒng)開銷作為代價的,甚至可能造成死鎖,所以盡量避免無謂的同步控制。synchronize方法被調(diào)用時,直接會把當(dāng)前對象鎖 了,在方法執(zhí)行完之前其他線程無法調(diào)用當(dāng)前對象的其他方法。所以synchronize的方法盡量小,并且應(yīng)盡量使用方法同步代替代碼塊同步。
9. 盡量不要使用finalize方法
實際上,將資源清理放在finalize方法中完成是非常不好的選擇,由于GC的工作量很大,尤其是回收Young代內(nèi)存時,大都會引起應(yīng)用程序暫停,所以再選擇使用finalize方法進(jìn)行資源清理,會導(dǎo)致GC負(fù)擔(dān)更大,程序運行效率更差。
10. 盡量使用基本數(shù)據(jù)類型代替對象
String str = "hello";
上面這種方式會創(chuàng)建一個“hello”字符串,而且JVM的字符緩存池還會緩存這個字符串;
String str = new String("hello");
此時程序除創(chuàng)建字符串外,str所引用的String對象底層還包含一個char[]數(shù)組,這個char[]數(shù)組依次存放了h,e,l,l,o
11. 多線程在未發(fā)生線程安全前提下應(yīng)盡量使用HashMap、ArrayList
HashTable、Vector等使用了同步機(jī)制,降低了性能。
12. 盡量合理的創(chuàng)建HashMap
當(dāng)你要創(chuàng)建一個比較大的hashMap時,充分利用這個構(gòu)造函數(shù)
public?HashMap(int?initialCapacity,?float?loadFactor);
避免HashMap多次進(jìn)行了hash重構(gòu),擴(kuò)容是一件很耗費性能的事,在默認(rèn)中initialCapacity只有16,而loadFactor是 0.75,需要多大的容量,你最好能準(zhǔn)確的估計你所需要的最佳大小,同樣的Hashtable,Vectors也是一樣的道理。
13. 盡量減少對變量的重復(fù)計算
如:
for(int?i=0;i應(yīng)該改為
for(int?i=0,len=list.size();i并且在循環(huán)中應(yīng)該避免使用復(fù)雜的表達(dá)式,在循環(huán)中,循環(huán)條件會被反復(fù)計算,如果不使用復(fù)雜表達(dá)式,而使循環(huán)條件值不變的話,程序?qū)\行的更快。
14. 盡量避免不必要的創(chuàng)建
如:
A?a?=?new?A();
if(i==1){list.add(a);}
應(yīng)該改為
if(i==1){
??A?a?=?new?A();
??list.add(a);
}
15. 盡量在finally塊中釋放資源
程序中使用到的資源應(yīng)當(dāng)被釋放,以避免資源泄漏。這最好在finally塊中去做。不管程序執(zhí)行的結(jié)果如何,finally塊總是會執(zhí)行的,以確保資源的正確關(guān)閉。
16. 盡量使用移位來代替'a/b'的操作
"/"是一個代價很高的操作,使用移位的操作將會更快和更有效
如
int?num?=?a?/?4;
int?num?=?a?/?8;
應(yīng)該改為
int?num?=?a?>>?2;
int?num?=?a?>>?3;
但注意的是使用移位應(yīng)添加注釋,因為移位操作不直觀,比較難理解
17.盡量使用移位來代替'a*b'的操作
同樣的,對于'*'操作,使用移位的操作將會更快和更有效
如
int?num?=?a?*?4;
int?num?=?a?*?8;
應(yīng)該改為
int?num?=?a?<2;
int?num?=?a?<3;
18. 盡量確定StringBuffer的容量
StringBuffer 的構(gòu)造器會創(chuàng)建一個默認(rèn)大?。ㄍǔJ?6)的字符數(shù)組。在使用中,如果超出這個大小,就會重新分配內(nèi)存,創(chuàng)建一個更大的數(shù)組,并將原先的數(shù)組復(fù)制過來,再 丟棄舊的數(shù)組。在大多數(shù)情況下,你可以在創(chuàng)建 StringBuffer的時候指定大小,這樣就避免了在容量不夠的時候自動增長,以提高性能。
如:
StringBuffer?buffer?=?new?StringBuffer(1000);
19. 盡量早釋放無用對象的引用
大部分時,方法局部引用變量所引用的對象 會隨著方法結(jié)束而變成垃圾,因此,大部分時候程序無需將局部,引用變量顯式設(shè)為null。
例如:
Java代碼
Public?void?test(){?
??Object?obj?=?new?Object();?
??……?
??Obj=null;?
}
上面這個就沒必要了,隨著方法test()的執(zhí)行完成,程序中obj引用變量的作用域就結(jié)束了。但是如果是改成下面:
Java代碼
Public?void?test(){?
??Object?obj?=?new?Object();?
??……?
??Obj=null;?
??//執(zhí)行耗時,耗內(nèi)存操作;或調(diào)用耗時,耗內(nèi)存的方法
??……?
}
這時候就有必要將obj賦值為null,可以盡早的釋放對Object對象的引用。
20. 盡量避免使用二維數(shù)組
二維數(shù)據(jù)占用的內(nèi)存空間比一維數(shù)組多得多,大概10倍以上。
關(guān)注公眾號:Java項目精選,回復(fù):666領(lǐng)取資料 。
21. 盡量避免使用split
除非是必須的,否則應(yīng)該避免使用split,split由于支持正則表達(dá)式,所以效率比較低,如果是頻繁的幾十,幾百萬的調(diào)用將會耗費大量資源,如果確實需要頻繁的調(diào)用split,可以考慮使用apache的StringUtils.split(string,char),頻繁split的可以緩存結(jié)果。
22. ArrayList & LinkedList
一個是線性表,一個是鏈表,一句話,隨機(jī)查詢盡量使用ArrayList,ArrayList優(yōu)于LinkedList,LinkedList還要移動指針,添加刪除的操作LinkedList優(yōu)于ArrayList,ArrayList還要移動數(shù)據(jù),不過這是理論性分析,事實未必如此,重要的是理解好2者得數(shù)據(jù)結(jié)構(gòu),對癥下藥。
23. 盡量使用System.arraycopy ()代替通過來循環(huán)復(fù)制數(shù)組
System.arraycopy() 要比通過循環(huán)來復(fù)制數(shù)組快的多
24. 盡量緩存經(jīng)常使用的對象
盡可能將經(jīng)常使用的對象進(jìn)行緩存,可以使用數(shù)組,或HashMap的容器來進(jìn)行緩存,但這種方式可能導(dǎo)致系統(tǒng)占用過多的緩存,性能下降,推薦可以使用一些第三方的開源工具,如EhCache,Oscache進(jìn)行緩存,他們基本都實現(xiàn)了FIFO/FLU等緩存算法。
25. 盡量避免非常大的內(nèi)存分配
有時候問題不是由當(dāng)時的堆狀態(tài)造成的,而是因為分配失敗造成的。分配的內(nèi)存塊都必須是連續(xù)的,而隨著堆越來越滿,找到較大的連續(xù)塊越來越困難。
26. 慎用異常
當(dāng)創(chuàng)建一個異常時,需要收集一個棧跟蹤(stack track),這個棧跟蹤用于描述異常是在何處創(chuàng)建的。構(gòu)建這些棧跟蹤時需要為運行時棧做一份快照,正是這一部分開銷很大。當(dāng)需要創(chuàng)建一個 Exception 時,JVM 不得不說:先別動,我想就您現(xiàn)在的樣子存一份快照,所以暫時停止入棧和出棧操作。棧跟蹤不只包含運行時棧中的一兩個元素,而是包含這個棧中的每一個元素。
如果您創(chuàng)建一個 Exception ,就得付出代價。好在捕獲異常開銷不大,因此可以使用 try-catch 將核心內(nèi)容包起來。從技術(shù)上講,您甚至可以隨意地拋出異常,而不用花費很大的代價。招致性能損失的并不是 throw 操作——盡管在沒有預(yù)先創(chuàng)建異常的情況下就拋出異常是有點不尋常。真正要花代價的是創(chuàng)建異常。幸運的是,好的編程習(xí)慣已教會我們,不應(yīng)該不管三七二十一就拋出異常。異常是為異常的情況而設(shè)計的,使用時也應(yīng)該牢記這一原則。
27. 盡量重用對象
特別是String對象的使用中,出現(xiàn)字符串連接情況時應(yīng)使用StringBuffer代替,由于系統(tǒng)不僅要花時間生成對象,以后可能還需要花時間對這些對象進(jìn)行垃圾回收和處理。因此生成過多的對象將會給程序的性能帶來很大的影響。
28. 不要重復(fù)初始化變量
默認(rèn)情況下,調(diào)用類的構(gòu)造函數(shù)時,java會把變量初始化成確定的值,所有的對象被設(shè)置成null,整數(shù)變量設(shè)置成0,float和double變量設(shè)置成0.0,邏輯值設(shè)置成false。當(dāng)一個類從另一個類派生時,這一點尤其應(yīng)該注意,因為用new關(guān)鍵字創(chuàng)建一個對象時,構(gòu)造函數(shù)鏈中的所有構(gòu)造函數(shù)都會被自動調(diào)用。這里有個注意,給成員變量設(shè)置初始值但需要調(diào)用其他方法的時候,最好放在一個方法比如initXXX()中,因為直接調(diào)用某方法賦值可能會因為類尚未初始化而拋空指針異常,如:public int state = this.getState();
29. 在java+Oracle的應(yīng)用系統(tǒng)開發(fā)中,java中內(nèi)嵌的SQL語言應(yīng)盡量使用大寫形式,以減少Oracle解析器的解析負(fù)擔(dān)。
30. 在java編程過程中,進(jìn)行數(shù)據(jù)庫連接,I/O流操作,在使用完畢后,及時關(guān)閉以釋放資源。因為對這些大對象的操作會造成系統(tǒng)大的開銷。
31. 過分的創(chuàng)建對象會消耗系統(tǒng)的大量內(nèi)存,嚴(yán)重時,會導(dǎo)致內(nèi)存泄漏,因此,保證過期的對象的及時回收具有重要意義。JVM的GC并非十分智能,因此建議在對象使用完畢后,手動設(shè)置成null。
32. 在使用同步機(jī)制時,應(yīng)盡量使用方法同步代替代碼塊同步**。**
33. 不要在循環(huán)中使用Try/Catch語句,應(yīng)把Try/Catch放在循環(huán)最外層
Error是獲取系統(tǒng)錯誤的類,或者說是虛擬機(jī)錯誤的類。不是所有的錯誤Exception都能獲取到的,虛擬機(jī)報錯Exception就獲取不到,必須用Error獲取。
34. 通過StringBuffer的構(gòu)造函數(shù)來設(shè)定他的初始化容量,可以明顯提升性能
StringBuffer的默認(rèn)容量為16,當(dāng)StringBuffer的容量達(dá)到最大容量時,她會將自身容量增加到當(dāng)前的2倍+2,也就是2*n+2。無論何時,只要StringBuffer到達(dá)她的最大容量,她就不得不創(chuàng)建一個新的對象數(shù)組,然后復(fù)制舊的對象數(shù)組,這會浪費很多時間。所以給StringBuffer設(shè)置一個合理的初始化容量值,是很有必要的!
35. 合理使用java.util.Vector
Vector與StringBuffer類似,每次擴(kuò)展容量時,所有現(xiàn)有元素都要賦值到新的存儲空間中。Vector的默認(rèn)存儲能力為10個元素,擴(kuò)容加倍。vector.add(index,obj) 這個方法可以將元素obj插入到index位置,但index以及之后的元素依次都要向下移動一個位置(將其索引加 1)。除非必要,否則對性能不利。同樣規(guī)則適用于remove(int index)方法,移除此向量中指定位置的元素。將所有后續(xù)元素左移(將其索引減 1)。返回此向量中移除的元素。所以刪除vector最后一個元素要比刪除第1個元素開銷低很多。刪除所有元素最好用removeAllElements()方法。如果要刪除vector里的一個元素可以使用 vector.remove(obj);而不必自己檢索元素位置,再刪除,如int index = indexOf(obj);vector.remove(index);
38. 不用new關(guān)鍵字創(chuàng)建對象的實例
用new關(guān)鍵詞創(chuàng)建類的實例時,構(gòu)造函數(shù)鏈中的所有構(gòu)造函數(shù)都會被自動調(diào)用。但如果一個對象實現(xiàn)了Cloneable接口,我們可以調(diào)用她的clone()方法。clone()方法不會調(diào)用任何類構(gòu)造函數(shù)。下面是Factory模式的一個典型實現(xiàn):
public?static?Credit?getNewCredit()?
{?
????return?new?Credit();?
}
改進(jìn)后的代碼使用clone()方法:
private?static?Credit?BaseCredit?=?new?Credit();?
public?static?Credit?getNewCredit()?
{?
????return?(Credit)BaseCredit.clone();?
}
39. 不要將數(shù)組聲明為:public static final
40. HaspMap的遍歷:
Map?paraMap?=?new?HashMap();?
for(?Entry?entry?:?paraMap.entrySet()?)?
{?
????String?appFieldDefId?=?entry.getKey();?
????String[]?values?=?entry.getValue();?
}
利用散列值取出相應(yīng)的Entry做比較得到結(jié)果,取得entry的值之后直接取key和value。
41. array(數(shù)組)和ArrayList的使用
array 數(shù)組效率最高,但容量固定,無法動態(tài)改變,ArrayList容量可以動態(tài)增長,但犧牲了效率。
42. 單線程應(yīng)盡量使用 HashMap, ArrayList,除非必要,否則不推薦使用HashTable,Vector,她們使用了同步機(jī)制,而降低了性能。
43. StringBuffer,StringBuilder的區(qū)別在于:java.lang.StringBuffer 線程安全的可變字符序列。一個類似于String的字符串緩沖區(qū),但不能修改。StringBuilder與該類相比,通常應(yīng)該優(yōu)先使用StringBuilder類,因為她支持所有相同的操作,但由于她不執(zhí)行同步,所以速度更快。為了獲得更好的性能,在構(gòu)造StringBuffer或StringBuilder時應(yīng)盡量指定她的容量。當(dāng)然如果不超過16個字符時就不用了。相同情況下,使用StringBuilder比使用StringBuffer僅能獲得10%~15%的性能提升,但卻要冒多線程不安全的風(fēng)險。綜合考慮還是建議使用StringBuffer。
44. 盡量使用基本數(shù)據(jù)類型代替對象。?
45. 使用具體類比使用接口效率高,但結(jié)構(gòu)彈性降低了,但現(xiàn)代IDE都可以解決這個問題。
46. 考慮使用靜態(tài)方法,如果你沒有必要去訪問對象的外部,那么就使你的方法成為靜態(tài)方法。她會被更快地調(diào)用,因為她不需要一個虛擬函數(shù)導(dǎo)向表。這同事也是一個很好的實踐,因為她告訴你如何區(qū)分方法的性質(zhì),調(diào)用這個方法不會改變對象的狀態(tài)。
47. 應(yīng)盡可能避免使用內(nèi)在的GET,SET方法。
48.避免枚舉,浮點數(shù)的使用。
以下舉幾個實用優(yōu)化的例子:
一、避免在循環(huán)條件中使用復(fù)雜表達(dá)式
在不做編譯優(yōu)化的情況下,在循環(huán)中,循環(huán)條件會被反復(fù)計算,如果不使用復(fù)雜表達(dá)式,而使循環(huán)條件值不變的話,程序?qū)\行的更快。例子:
import?java.util.Vector;?
class?CEL?{?
?????void?method?(Vector?vector)?{?
?????????for?(int?i?=?0;?i??????????????;?//?...?
?????}?
}
更正:
class?CEL_fixed?{?
?????void?method?(Vector?vector)?{?
?????????int?size?=?vector.size?()?
?????????for?(int?i?=?0;?i??????????????;?//?...?
?????}?
}
二、為'Vectors' 和 'Hashtables'定義初始大小
JVM為Vector擴(kuò)充大小的時候需要重新創(chuàng)建一個更大的數(shù)組,將原原先數(shù)組中的內(nèi)容復(fù)制過來,最后,原先的數(shù)組再被回收。可見Vector容量的擴(kuò)大是一個頗費時間的事。
通常,默認(rèn)的10個元素大小是不夠的。你最好能準(zhǔn)確的估計你所需要的最佳大小。例子:
import?java.util.Vector;
public?class?DIC?{
public?void?addObjects?(Object[]?o)?{
//?if?length?>?10,?Vector?needs?to?expand
for?(int?i?=?0;?iv.add(o);??//?capacity?before?it?can?add?more?elements.
}
}
public?Vector?v?=?new?Vector();??//?no?initialCapacity.
}
更正:
自己設(shè)定初始大小。
public Vector v = new Vector(20); public Hashtable hash = new Hashtable(10);
三、在finally塊中關(guān)閉Stream
程序中使用到的資源應(yīng)當(dāng)被釋放,以避免資源泄漏。這最好在finally塊中去做。不管程序執(zhí)行的結(jié)果如何,finally塊總是會執(zhí)行的,以確保資源的正確關(guān)閉。
四、使用'System.arraycopy ()'代替通過來循環(huán)復(fù)制數(shù)組,例子:
public?class?IRB
{
void?method?()?{
int[]?array1?=?new?int?[100];
for?(int?i?=?0;?i?array1?[i]?=?i;
}
int[]?array2?=?new?int?[100];
for?(int?i?=?0;?i?array2?[i]?=?array1?[i];?//?Violation
}
}
}
更正:
public?class?IRB
{
void?method?()?{
int[]?array1?=?new?int?[100];
for?(int?i?=?0;?i?array1?[i]?=?i;
}
int[]?array2?=?new?int?[100];
System.arraycopy(array1,?0,?array2,?0,?100);
}
}
五、讓訪問實例內(nèi)變量的getter/setter方法變成”final”
簡單的getter/setter方法應(yīng)該被置成final,這會告訴編譯器,這個方法不會被重載,所以,可以變成”inlined”,例子:
class?MAF?{
public?void?setSize?(int?size)?{
_size?=?size;
}
private?int?_size;
}
更正:
class?DAF_fixed?{
final?public?void?setSize?(int?size)?{
_size?=?size;
}
private?int?_size;
}
六、對于常量字符串,用'String' 代替 'StringBuffer'
常量字符串并不需要動態(tài)改變長度。
例子:
public?class?USC?{
String?method?()?{
StringBuffer?s?=?new?StringBuffer?("Hello");
String?t?=?s?+?"World!";
return?t;
}
}
更正:把StringBuffer換成String,如果確定這個String不會再變的話,這將會減少運行開銷提高性能。
七、在字符串相加的時候,使用 ' ' 代替 " ",如果該字符串只有一個字符的話
例子:
public?class?STR?{
public?void?method(String?s)?{
String?string?=?s?+?"d"??//?violation.
string?=?"abc"?+?"d"????//?violation.
}
}
更正:
將一個字符的字符串替換成' '
public?class?STR?{
public?void?method(String?s)?{
String?string?=?s?+?'d'
string?=?"abc"?+?'d'?
}
}
以上僅是Java方面編程時的性能優(yōu)化,性能優(yōu)化大部分都是在時間、效率、代碼結(jié)構(gòu)層次等方面的權(quán)衡,各有利弊,不要把上面內(nèi)容當(dāng)成教條,或許有些對我們實際工作適用,有些不適用,還望根據(jù)實際工作場景進(jìn)行取舍吧,活學(xué)活用,變通為宜。
最近面試BAT,整理一份面試資料《Java面試BAT通關(guān)手冊》,覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫、數(shù)據(jù)結(jié)構(gòu)等等。 獲取方式:關(guān)注公眾號并回復(fù)?java?領(lǐng)取,更多內(nèi)容陸續(xù)奉上。 明天見(??ω??)??
