Java 性能優(yōu)化的 55 個(gè)細(xì)節(jié)(珍藏版)

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