1.盡量指定類即供、方法的final修飾符
2.盡量重用對象
3.盡可能使用局部變量
4.及時關閉流
5.盡量減少對變量的重復計算
例如捣染,將
for (int i = 0; i < list.size(); i++) {
...
}
替換為:
for (int i = 0, int length = list.size(); i < length; i++) {
...
}
6.盡量采用懶加載的策略霜第,即在需要的時候才創(chuàng)建
例如矿咕,將
String str = "aaa";
if (i == 1){
list.add(str);
}
替換為:
if (i == 1){
String str = "aaa";
list.add(str);
}
7.慎用異常
異常對性能不利名挥。拋出異常首先要創(chuàng)建一個新的對象,Throwable接口的構造函數(shù)調(diào)用名為fillInStackTrace()的本地同步方法县好,fillInStackTrace()方法檢查堆棧围橡,收集調(diào)用跟蹤信息。只要有異常被拋出缕贡,Java虛擬機就必須調(diào)整調(diào)用堆棧翁授,因為在處理過程中創(chuàng)建了一個新的對象。異常只能用于錯誤處理晾咪,不應該用來控制程序流程收擦。
8.不要在循環(huán)中使用try {} catch {},應該把其放在最外層
9.如果能估計到待添加的內(nèi)容長度谍倦,為底層以數(shù)組方式實現(xiàn)的集合塞赂、工具類指定初始長度
比如ArrayList、LinkedLlist昼蛀、StringBuilder减途、StringBuffer、HashMap曹洽、HashSet等等,以StringBuilder為例:
- (1)StringBuilder() // 默認分配16個字符的空間
- (2)StringBuilder(int size) // 默認分配size個字符的空間
- (3)StringBuilder(String str) // 默認分配16個字符+str.length()個字符空間
可以通過類(這里指的不僅僅是上面的StringBuilder)的來設定它的初始化容量辽剧,這樣可以明顯地提升性能送淆。比如StringBuilder吧,length表示當前的StringBuilder能保持的字符數(shù)量怕轿。因為當StringBuilder達到最大容量的時候偷崩,它會將自身容量增加到當前的2倍再加2,無論何時只要StringBuilder達到它的最大容量撞羽,它就不得不創(chuàng)建一個新的字符數(shù)組然后將舊的字符數(shù)組內(nèi)容拷貝到新字符數(shù)組中—-這是十分耗費性能的一個操作阐斜。試想,如果能預估到字符數(shù)組中大概要存放5000個字符而不指定長度诀紊,最接近5000的2次冪是4096谒出,每次擴容加的2不管,那么:
(1)在4096 的基礎上邻奠,再申請8194個大小的字符數(shù)組笤喳,加起來相當于一次申請了12290個大小的字符數(shù)組,如果一開始能指定5000個大小的字符數(shù)組碌宴,就節(jié)省了一倍以上的空間
(2)把原來的4096個字符拷貝到新的的字符數(shù)組中去
這樣杀狡,既浪費內(nèi)存空間又降低代碼運行效率。所以贰镣,給底層以數(shù)組實現(xiàn)的集合呜象、工具類設置一個合理的初始化容量是錯不了的膳凝,這會帶來立竿見影的效果。但是恭陡,注意蹬音,像HashMap這種是以數(shù)組+鏈表實現(xiàn)的集合,別把初始大小和你估計的大小設置得一樣子姜,因為一個table上只連接一個對象的可能性幾乎為0祟绊。初始大小建議設置為2的N次冪,如果能估計到有2000個元素哥捕,設置成new HashMap(128)牧抽、new HashMap(256)都可以。
10.當復制大量數(shù)據(jù)時遥赚,使用System.arraycopy()命令
11.乘法和除法使用移位操作
12.盡量避免隨意使用靜態(tài)變量
當某個對象被定義為static的變量所引用扬舒,那么gc通常是不會回收這個對象所占有的堆內(nèi)存的
13.實現(xiàn)RandomAccess接口的集合比如ArrayList,應當使用最普通的for循環(huán)而不是foreach循環(huán)來遍歷
這是JDK推薦給用戶的凫佛。JDK API對于RandomAccess接口的解釋是:實現(xiàn)RandomAccess接口用來表明其支持快速隨機訪問讲坎,此接口的主要目的是允許一般的算法更改其行為,從而將其應用到隨機或連續(xù)訪問列表時能提供良好的性能愧薛。實際經(jīng)驗表明晨炕,實現(xiàn)RandomAccess接口的類實例,假如是隨機訪問的毫炉,使用普通for循環(huán)效率將高于使用foreach循環(huán)瓮栗;反過來,如果是順序訪問的瞄勾,則使用Iterator會效率更高费奸。
foreach循環(huán)的底層實現(xiàn)原理就是迭代器Iterator,參見Java語法糖1:可變長度參數(shù)以及foreach循環(huán)原理进陡。所以后半句”反過來愿阐,如果是順序訪問的,則使用Iterator會效率更高”的意思就是順序訪問的那些類實例趾疚,使用foreach循環(huán)去遍歷缨历。
14.將常量聲明為static final,并以大寫命名
這樣在編譯期間就可以把這些內(nèi)容放入常量池中盗蟆,避免運行期間計算生成常量的值戈二。另外,將常量的名字以大寫命名也可以方便區(qū)分出常量與變量
15.順序插入和隨機訪問比較多的場景使用ArrayList喳资,元素刪除和中間插入比較多的場景使用LinkedList
16.把一個基本數(shù)據(jù)類型轉為字符串觉吭,基本數(shù)據(jù)類型.toString()是最快的方式、String.valueOf(數(shù)據(jù))次之仆邓、數(shù)據(jù)+”"最慢
- 1)String.valueOf()方法底層調(diào)用了Integer.toString()方法鲜滩,但是會在調(diào)用前做空判斷
- 2)Integer.toString()方法就不說了伴鳖,直接調(diào)用了
- 3)i + “”底層使用了StringBuilder實現(xiàn),先用append方法拼接徙硅,再用toString()方法獲取字符串
17.使用最有效率的方式去遍歷Map
假如只想遍歷Map的key榜聂,則調(diào)用 keySet()比較合適.
假如遍歷key和value,則調(diào)用entrySet()最合適.