寫(xiě)Java也有n年了,現在還是有不少的壞的代碼習慣,也通過(guò)學(xué)習別人的代碼學(xué)到了不少好的習慣。這篇文章主要是整理的資料。留給自己做個(gè)警戒,提示以后寫(xiě)代碼的時(shí)候注意!在文章的后面,會(huì )提供整理的原材料下載。
一、類(lèi)和對象使用技巧
1、盡量少用new生成新對象
用new創(chuàng )建類(lèi)的實(shí)例時(shí),構造雨數鏈中所有構造函數都會(huì )被自動(dòng)調用,操作速度較慢。在某些時(shí)候可復用現有對象。比如在進(jìn)行大量St rillg操作時(shí),可用StringBuffer婁代替String類(lèi),以避免生成大量的對象。用 new關(guān)鍵詞創(chuàng )建類(lèi)的實(shí)例時(shí),構造函數鏈中的所有構造函數都會(huì )被自動(dòng)調用。但如果一個(gè)對象實(shí)現了 Cloneable 接口,我們可以調用她的 clone() 方法。clone()方法不會(huì )調用任何類(lèi)構造函數。
下面是 Factory 模式的一個(gè)典型實(shí)現。
- public static Credit getNewCredit()
改進(jìn)后的代碼使用 clone() 方法,
- private static Credit BaseCredit = new Credit();
- public static Credit getNewCredit()
- {
- return (Credit)BaseCredit.clone();
- }
2、使用clone()方法生成新對象
如果一個(gè)對象實(shí)現Cloneable接口,就可以調用它的clone()方法。clone()方法不會(huì )淚用任何類(lèi)構造函數,比使用new方法創(chuàng )建實(shí)例速度要快。
3、盡量使用局部變量(棧變量)
調用方法時(shí)傳遞的參數及調用中創(chuàng )建的臨時(shí)變量保存在棧(Stack)中,速度較快。其他變量,如靜態(tài)變量、實(shí)例變量都在堆(HeaP)中創(chuàng )建,速度較慢。訪(fǎng)問(wèn)靜態(tài)變量和實(shí)例變量將會(huì )比訪(fǎng)問(wèn)局部變量多耗費 2-3 個(gè)時(shí)鐘周期。如果一個(gè)變量需要經(jīng)常訪(fǎng)問(wèn),那么你就需要考慮這個(gè)變量的作用域了。static? local?還是實(shí)例變量?
調用方法時(shí)傳遞的參數以及在調用中創(chuàng )建的臨時(shí)變量都保存在棧(Stack)中,速度較快。其他變量,如靜態(tài)變量,實(shí)例變量等,都在堆(Heap)中創(chuàng )建,速度較慢。
例子:
- public class usv {
- void getsum (int[] values) {
- for (int i=0; i < value.length; i++) {
- _sum += value[i];
- }
- }
- void getsum2 (int[] values) {
- for (int i=0; i < value.length; i++) {
- _staticsum += value[i];
- }
- }
- private int _sum;
- private static int _staticsum;
- }
-
更正:如果可能,請使用局部變量作為你經(jīng)常訪(fǎng)問(wèn)的變量。 你可以按下面的方法來(lái)修改 getsum()方法: - void getsum (int[] values) {
- int sum = _sum;
- for (int i=0; i < value.length; i++) {
- sum += value[i];
- }
- _sum = sum;
4、減少方法調用
面向對象設計的一個(gè)基本準則是通過(guò)方法間接訪(fǎng)問(wèn)對象的屬性,但方法調用會(huì )占用·些開(kāi)銷(xiāo)訪(fǎng)問(wèn)??梢员苊庠谕粋€(gè)類(lèi)中通過(guò)訓州函數或方法(get或set)來(lái)設置或調用該對象的災例變量,這比直接訪(fǎng)問(wèn)變量要慢。為了減少方法調用,可以將方法中的代碼復制到調用方法的地方,比如大量的循環(huán)中,這樣可以節省方法調用的開(kāi)銷(xiāo)。但帶來(lái)性能提升的同時(shí)會(huì )犧牲代碼的可讀性,可根據實(shí)際需要平衡兩者關(guān)系。
5、使用final類(lèi)和final、static、private方法
帶有final修飾符的類(lèi)是不可派生的。如果指定一個(gè)類(lèi)為finaI,則該類(lèi)所有的方法都是final。JAVA編障器會(huì )尋找機會(huì )內聯(lián)(inIine)所有的final方法。此舉能夠提升程序性能。使用final、static、private的方法是不能被覆蓋的,JAVA不需要在稃序運行的時(shí)候動(dòng)態(tài)關(guān)聯(lián)實(shí)現方法,從而節省了運行時(shí)間。
帶有 final 修飾符的類(lèi)是不可派生的。在 JAVA核心 API中,有許多應用 final 的例子,例如 java.lang.String。為 String 類(lèi)指定 final 防止了使用者覆蓋 length()方法。另外,如果一個(gè)類(lèi)是 final 的,則該類(lèi)所有方法都是 final 的。java 編譯器會(huì )尋找機會(huì )內聯(lián)(inline)所有的final 方法(這和具體的編譯器實(shí)現有關(guān))。此舉能夠使性能平均提高 50%。
6、讓訪(fǎng)問(wèn)實(shí)例內變量的 getter/setter 方法變成”final”
簡(jiǎn)單的 getter/setter 方法應該被置成 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;
- }
7、避免不需要的 instanceof 操作
如果左邊的對象的靜態(tài)類(lèi)型等于右邊的,instanceof 表達式返回永遠為 true。
例子:
- public class uiso {
- public uiso () {}
- }
- class dog extends uiso {
- void method (dog dog, uiso u) {
- dog d = dog;
- if (d instanceof uiso)
- system.out.println("dog is a uiso");
- uiso uiso = u;
- if (uiso instanceof object)
- system.out.println("uiso is an object");
- }
- }
更正:刪掉不需要的 instanceof 操作。
- class dog extends uiso {
- void method () {
- dog d;
- system.out.println ("dog is an uiso");
- system.out.println ("uiso is an uiso");
- }
- }
8、避免不需要的造型操作
所有的類(lèi)都是直接或者間接繼承自 object。同樣,所有的子類(lèi)也都隱含的“等于”其父類(lèi)。那么,由子類(lèi)造型至父類(lèi)的操作就是不必要的了。
例子:
- class unc {
- string _id = "unc";
- }
- class dog extends unc {
- void method () {
- dog dog = new dog ();
- unc animal = (unc)dog;
- object o = (object)dog;
- }
- }
更正: - class dog extends unc {
- void method () {
- dog dog = new dog();
- unc animal = dog;
- object o = dog;
- }
- }
9.盡量重用對象。
特別是 String 對象的使用中,出現字符串連接情況時(shí)應使用 StringBuffer 代替,由于系統不僅要花時(shí)間生成對象,以后可能還需要花時(shí)間對這些對象進(jìn)行垃圾回收和處理。因此生成過(guò)多的對象將會(huì )給程序的性能帶來(lái)很大的影響。
10、不要重復初始化變量。
默認情況下,調用類(lèi)的構造函數時(shí),java 會(huì )把變量初始化成確定的值,所有的對象被設置成null,整數變量設置成 0,float 和 double 變量設置成 0.0,邏輯值設置成 false。當一個(gè)類(lèi)從另一個(gè)類(lèi)派生時(shí),這一點(diǎn)尤其應該注意,因為用 new 關(guān)鍵字創(chuàng )建一個(gè)對象時(shí),構造函數鏈中的所有構造函數都會(huì )被自動(dòng)調用。 這里有個(gè)注意,給成員變量設置初始值但需要調用其他方法的時(shí)候,最好放在一個(gè)方法比如initXXX()中,因為直接調用某方法賦值可能會(huì )因為類(lèi)尚未初始化而拋空指針異常,public int state = this.getState();
11、不要過(guò)分創(chuàng )建對象
過(guò)分的創(chuàng )建對象會(huì )消耗系統的大量?jì)却?,嚴重時(shí),會(huì )導致內存泄漏,因此,保證過(guò)期的對象的及時(shí)回收具有重要意義。 JVM 的 GC并非十分智能,因此建議在對象使用完畢后,手動(dòng)設置成 null。
二、Java I/O技巧
I/O性能常常是應用程序性能瓶頸,優(yōu)化I/O性能就顯得極為系要。在進(jìn)行I/0操作時(shí),匿遵循以下原則:盡可能少的訪(fǎng)問(wèn)磁盤(pán);盡可能少的I方問(wèn)底層的操作系統;盡可能少的方法調用;盡可能少處理個(gè)別的處理字節和字符?;谝陨显瓌t,可以通過(guò)以下技巧提高I/O速度:1、使州緩沖提高I/O性能。
常用的實(shí)現方法有以下2種:使用用于字符的BufferedReader和用于寧節的BufferedlnputStream類(lèi),或者使用塊讀取方法次讀取一大塊數據。
2、lnputStream比Reader高效,OutputStream比Writer高效。
當使用Unicode字符串時(shí),Write類(lèi)的開(kāi)銷(xiāo)比較大。因為它要實(shí)Uoicode到字節(byte)的轉換。因此,如果可能的話(huà),在使用 Write類(lèi)之前就實(shí)現轉換或用OutputStream類(lèi)代替Writer婁來(lái)使用。
3、在適當的時(shí)候用byte替代char。
1個(gè)char用2個(gè)字節保存字符,而byte只需要1個(gè),因此用byte保存字符消耗的內存和需要執行的機器指令更少。更重要的是,用byte避免了進(jìn)行Unicode轉換。因此,如果町能的話(huà),應盡量使用byte替代char。
4、有緩沖的塊操作10要比緩沖的流字符IO快。
對于字符IO,雖然緩沖流避免了每次讀取字符時(shí)的系統調用開(kāi)銷(xiāo),但仍需要一次或多次方法調用。帶緩沖的塊10比緩沖流IO快2到4倍,比無(wú)緩沖的IO快4到40倍。
5、序列化時(shí),使用原子類(lèi)型。
當序列化一個(gè)類(lèi)或對象時(shí),對干那些原子類(lèi)型(atomic)或可以重建的元素,要標識為transient類(lèi)型,這樣就不用每一次都進(jìn)行序列化。如果這砦序列化的對象要在網(wǎng)絡(luò )上傳輸,這一小小的改變對性能會(huì )有很大的提高。
6、在finally 塊中關(guān)閉stream
程序中使用到的資源應當被釋放,以避免資源泄漏。這最好在 finally 塊中去做。不管程序執行的結果如何,finally 塊總是會(huì )執行的,以確保資源的正確關(guān)閉。
例子:
- import java.io.*;
- public class cs {
- public static void main (string args[]) {
- cs cs = new cs ();
- cs.method ();
- }
- public void method () {
- try {
- fileinputstream fis = new fileinputstream ("cs.java");
- int count = 0;
- while (fis.read () != -1)
- count++;
- system.out.println (count);
- fis.close ();
- } catch (filenotfoundexception e1) {
- } catch (ioexception e2) {
- }
- }
- }
更正:
在最后一個(gè) catch 后添加一個(gè) finally 塊
7、SQL語(yǔ)句
在 java+Oracle 的應用系統開(kāi)發(fā)中,java 中內嵌的 SQL 語(yǔ)言應盡量使用大寫(xiě)形式,以減少Oracle 解析器的解析負擔。
8、盡早釋放資源
java 編程過(guò)程中,進(jìn)行數據庫連接,I/O 流操作,在使用完畢后,及時(shí)關(guān)閉以釋放資源。因為對這些大對象的操作會(huì )造成系統大的開(kāi)銷(xiāo)。
三、異常(Exceptions)使用技巧
JAVA語(yǔ)言中提供了try/catch來(lái)開(kāi)發(fā)方便用戶(hù)捕捉異常,進(jìn)行異常的處理。但是如果使用不當,也會(huì )給JAvA程序的性能帶來(lái)影響。因此,要注意以下兒點(diǎn)。慎用異常,異常對性能不利。拋出異常首先要創(chuàng )建一個(gè)新的對象。Throwable接口的構造函數調用名為fillInStackTrace()的本地(Native)方法filllnStackTrace()方法檢查堆棧,收集調用跟蹤信息。只要有異常被拋出,VM就必須調整調用堆棧。1、避免使用異常來(lái)控制程序流程
如果可以用if、while等邏輯語(yǔ)句來(lái)處理,那么就盡可能的不用try/catch語(yǔ)句。拋出異常首先要創(chuàng )建一個(gè)新的對象。Throwable 接口的構造函數調用名為 fillInStackTrace()的本地方法,fillInStackTrace()方法檢查棧,收集調用跟蹤信息。只要有異常被拋出,VM 就必須調整調用棧,因為在處理過(guò)程中創(chuàng )建了一個(gè)新的對象。 異常只能用于錯誤處理,不應該用來(lái)控制程序流程。
2、盡可能重用異常
在必須要進(jìn)行異常的處理時(shí),要盡可能的重用已經(jīng)存在的異常對象。因為在異常的處理中,生成個(gè)異常對象要消耗掉大部分的時(shí)間。
3、將try/catch 塊移出循環(huán)
把try/catch塊放入循環(huán)體內,會(huì )極大的影響性能,如果編譯 jit 被關(guān)閉或者你所使用的是一個(gè)不帶 jit 的jvm,性能會(huì )將下降21%之多!
例子:
- import java.io.fileinputstream;
- public class try {
- void method (fileinputstream fis) {
- for (int i = 0; i < size; i++) {
- try {
- _sum += fis.read();
- } catch (exception e) {}
- }
- }
- private int _sum;
- }
更正:將 try/catch塊移出循環(huán)
- void method (fileinputstream fis) {
- try {
- for (int i = 0; i < size; i++) { _sum += fis.read();
- }
- } catch (exception e) {}
- }
四、線(xiàn)程使用技巧
1、在使用大量線(xiàn)程(Threading)的場(chǎng)合使用線(xiàn)程池管理
生成和啟動(dòng)新線(xiàn)程是個(gè)相對較慢的過(guò)程,生成人量新線(xiàn)程會(huì )嚴重影響應J_}j程序性能。通過(guò)使用線(xiàn)程池,由線(xiàn)程池管理器(thread pool manager)來(lái)生成新線(xiàn)程或分配現有線(xiàn)程,柏省生成線(xiàn)程的叫間。
2、防止過(guò)多的同步
不必要的同步常常會(huì )造成程序性能的下降,調用同步方法比調用非同步方法要花費更多的時(shí)間。如果程序是單線(xiàn)程,則沒(méi)有必要使用同步。
3、同步方法而不要同步整個(gè)代碼段
對某個(gè)方法或函數進(jìn)行同步比對整個(gè)代碼段進(jìn)行同步的性能要好。
4、在追求速度的場(chǎng)合,用ArrayList和HashMap代替Vector和Hashtable
Vector和Hashtable實(shí)現了同步以提高線(xiàn)程安全性,但速度較沒(méi)有實(shí)現同步的ArrayList和Ha shMap要慢,可以根據需要選擇使用的類(lèi)。
5、使用notify()而不是notifyAll()
使用哪個(gè)方法要取決于程序的沒(méi)計,但應盡可能使用notify(),因為notify()只喚醒等待指定對象的線(xiàn)程,比喚醒所有等待線(xiàn)稃的notifyAll0速度更快。
6、不要在循環(huán)中調用 synchronized(同步)方法
方法的同步需要消耗相當大的資料,在一個(gè)循環(huán)中調用它絕對不是一個(gè)好主意。
例子:
- import java.util.vector;
- public class syn {
- public synchronized void method (object o) {
- }
- private void test () {
- for (int i = 0; i < vector.size(); i++) {
- method (vector.elementat(i));
- }
- }
- private vector vector = new vector (5, 5);
- }
更正:不要在循環(huán)體中調用同步方法,如果必須同步的話(huà),推薦以下方式:
- import java.util.vector;
- public class syn {
- public void method (object o) {
- }
- private void test () {
- synchronized{
- for (int i = 0; i < vector.size(); i++) {
- method (vector.elementat(i));
- }
- }
- }
- private vector vector = new vector (5, 5);
- }
7、單線(xiàn)程應盡量使用 HashMap, ArrayList。
除非必要,否則不推薦使用 HashTable,Vector,她們使用了同步機制,而降低了性能。
五、其它常用技巧
1、使用移位操作替代乘除法操作可以極大地提高性能
"/"是一個(gè)很“昂貴”的操作,使用移位操作將會(huì )更快更有效。
例子:
- public class sdiv {
- public static final int num = 16;
- public void calculate(int a) {
- int div = a / 4;
- int div2 = a / 8;
- int temp = a / 3;
- int mul = a * 4;
- int mul2 = 8 * a;
- int temp2 = a * 3;
- }
- }
更正:
- public class sdiv {
- public static final int num = 16;
- public void calculate(int a) {
- int div = a >> 2;
- int div2 = a >> 3;
- int temp = a / 3;
- int mul = a << 2;
- int mul2 = a << 3;
- int temp = a * 3;
- }
- }
PS:除非是在一個(gè)非常大的循環(huán)內,性能非常重要,而且你很清楚你自己在做什么,方可使用這種方法。否則提高性能所帶來(lái)的程序晚讀性的降低將是不合算的。
2、對Vector中最后位置的添加、刪除操作要遠遠快于塒第一個(gè)元素的添加、刪除操作
3、當復制數組時(shí),使用System.arraycop()方法
例子:
- public class irb
- {
- void method () {
- int[] array1 = new int [100];
- for (int i = 0; i < array1.length; i++) {
- array1 [i] = i;
- }
- int[] array2 = new int [100];
- for (int i = 0; i < array2.length; i++) {
- array2 [i] = array1 [i];
- }
- }
- }
更正:
- public class irb
- {
- void method () {
- int[] array1 = new int [100];
- for (int i = 0; i < array1.length; i++) {
- array1 [i] = i;
- }
- int[] array2 = new int [100];
- system.arraycopy(array1, 0, array2, 0, 100);
- }
- }
4、使用復合賦值運算符
a=a+b和a+b住編譯時(shí)會(huì )產(chǎn)生不同JAVA字奇碼,后者回快于前者。岡此,使用+=、-=、+=、/=等復臺賦值運算符會(huì )使運算速度稍有提升。
5、用int而不用其它基本類(lèi)型
對int類(lèi)犁的操作通常比其它基本類(lèi)型要快,因此盡量使用int類(lèi)型。
6、在進(jìn)行數據庫連接和網(wǎng)絡(luò )連接時(shí)使用連接池
這類(lèi)連接往往會(huì )耗費大量時(shí)間,應盡量避免??梢允褂眠B接池技術(shù),復用現有連接。
7、用壓縮加快網(wǎng)絡(luò )傳輸速度一種常用方法是把相關(guān)文件打包到一個(gè)jar文件中。
用一個(gè)Jar文件發(fā)送多個(gè)文件還叫以避免每個(gè)文件打開(kāi)和關(guān)閉網(wǎng)絡(luò )連接所造成的開(kāi)銷(xiāo)。
8、在數據庫應用程序中使用批處理功能
可以利用Statement類(lèi)的addBatch()氟l exexuteBatch法成批地提交sql語(yǔ)句,以節省網(wǎng)絡(luò )傳輸開(kāi)銷(xiāo)。在執行大量相似語(yǔ)句時(shí),可以使用PreParedState—類(lèi),它可以一次性編譯語(yǔ)句并多次執行,用參數最后執行的sql語(yǔ)句。
9、消除循環(huán)體中不必要的代碼
這似乎是每個(gè)程序員都知道的基本原則,沒(méi)有必出,但很多人往往忽略一些細節。如下列代碼:
- Vector aVector= ...;
- for(int i=0;i<aVector size();i++)(
- System out printlll(aVector elementAt(i)toStringO);
- }
這段代碼中沒(méi)循環(huán)一次就要調用aVector.size()方法,aVector的長(cháng)度不變的話(huà),可以改為一下代碼:
- Vector aVector= ...:
- int length=aVector size();
- for(int i=0;i<length;i++)f
- System out println(aVector elememAt(i)toStringO);
- )
這樣消除了每次調用aVector.size()方法的開(kāi)銷(xiāo)。
10、為'vectors' 和 'hashtables'定義初始大小
jvm 為 vector 擴充大小的時(shí)候需要重新創(chuàng )建一個(gè)更大的數組,將原原先數組中的內容復制過(guò)來(lái),最后,原先的數組再被回收??梢?jiàn) vector 容量的擴大是一個(gè)頗費時(shí)間的事。 通常,默認的 10 個(gè)元素大小是不夠的。你最好能準確的估計你所需要的最佳大小。
例子:
- import java.util.vector;
- public class dic {
- public void addobjects (object[] o) {
-
- for (int i = 0; i< o.length;i++) {
- v.add(o);
- }
- }
- public vector v = new vector();
- }
- <SPAN style="WHITE-SPACE: pre"> </SPAN><SPAN style="FONT-SIZE: 14px">更正: 自己設定初始大小。 </SPAN>
- public vector v = new vector(20);
- public hashtable hash = new hashtable(10);
11、如果只是查找單個(gè)字符的話(huà),用charat()代替startswith()
用一個(gè)字符作為參數調用 startswith()也會(huì )工作的很好,但從性能角度上來(lái)看,調用用 string api 無(wú)疑是錯誤的!
例子:
- public class pcts {
- private void method(string s) {
- if (s.startswith("a")) {
-
- }
- }
- }
更正 :將'startswith()' 替換成'charat()'.
- public class pcts {
- private void method(string s) {
- if ('a' == s.charat(0)) {
-
- }
- }
- }
12、在字符串相加的時(shí)候,使用 ' ' 代替 " ",如果該字符串只有一個(gè)字符的話(huà)
例子:
- public class str {
- public void method(string s) {
- string string = s + "d"
- string = "abc" + "d"
- }
- }
更正: 將一個(gè)字符的字符串替換成' '
- public class str {
- public void method(string s) {
- string string = s + 'd'
- string = "abc" + 'd'
- }
- }
13、對于 boolean 值,避免不必要的等式判斷
將一個(gè) boolean 值與一個(gè) true 比較是一個(gè)恒等操作(直接返回該 boolean 變量的值). 移走對于boolean 的不必要操作至少會(huì )帶來(lái) 2 個(gè)好處:
1)代碼執行的更快 (生成的字節碼少了 5 個(gè)字節);
2)代碼也會(huì )更加干凈 。
例子:
- public class ueq {
- boolean method (string string) {
- return string.endswith ("a") == true;
- }
- }
更正: - class ueq_fixed {
- boolean method (string string) {
- return string.endswith ("a");
- }
- }
14、對于常量字符串,用'string' 代替 'stringbuffer'
常量字符串并不需要動(dòng)態(tài)改變長(cháng)度。
例子:
- public class usc {
- string method () {
- stringbuffer s = new stringbuffer ("hello");
- string t = s + "world!";
- return t;
- }
- }
更正:
把 stringbuffer 換成 string,如果確定這個(gè) string 不會(huì )再變的話(huà),這將會(huì )減少運行開(kāi)銷(xiāo)提高性能。
15、用'stringtokenizer' 代替 'indexof()' 和'substring()'
字符串的分析在很多應用中都是常見(jiàn)的。使用 indexof()和 substring()來(lái)分析字符串容易導致 stringindexoutofboundsexception。而使用 stringtokenizer 類(lèi)來(lái)分析字符串則會(huì )容易一些,效率也會(huì )高一些。
例子:
- public class ust {
- void parsestring(string string) {
- int index = 0;
- while ((index = string.indexof(".", index)) != -1) {
- system.out.println (string.substring(index, string.length()));
- }
- }
- }
16、使用條件操作符替代"if (cond) else " 結構
條件操作符更加的簡(jiǎn)捷
例子:
- public class if {
- public int method(boolean isdone) {
- if (isdone) {
- return 0;
- } else {
- return 10;
- }
-
- void method2(boolean istrue) {
- if (istrue) {
- _value = 0;
- } else {
- _value = 1;
- <SPAN style="WHITE-SPACE: pre"> </SPAN>}
- }
- }
更正:
- public class if {
- public int method(boolean isdone) {
- return (isdone ? 0 : 10);
- }
-
- void method(boolean istrue) {
- <SPAN style="WHITE-SPACE: pre"> </SPAN>_value = (istrue ? 0 : 1);
- <SPAN style="WHITE-SPACE: pre"> </SPAN>}
- private int _value = 0;
-
- }
17、不要在循環(huán)體中實(shí)例化變量
在循環(huán)體中實(shí)例化臨時(shí)變量將會(huì )增加內存消耗
例子:
- import java.util.vector;
- public class loop {
- void method (vector v) {
- for (int i=0;i < v.size();i++) {
- object o = new object();
- o = v.elementat(i);
- }
- }
- }
更正:
在循環(huán)體外定義變量,并反復使用
- import java.util.vector;
- public class loop {
- void method (vector v) {
- object o;
- for (int i=0;i<v.size();i++) {
- o = v.elementat(i);
- }
- }
- }
18、確定 stringbuffer的容量
stringbuffer 的構造器會(huì )創(chuàng )建一個(gè)默認大小(通常是 16)的字符數組。在使用中,如果超出這個(gè)大小,就會(huì )重新分配內存,創(chuàng )建一個(gè)更大的數組,并將原先的數組復制過(guò)來(lái),再丟棄舊的數組。在大多數情況下,你可以在創(chuàng )建 stringbuffer 的時(shí)候指定大小,這樣就避免了在容量不夠的時(shí)候自動(dòng)增長(cháng),以提高性能。
例子:
- public class rsbc {
- void method () {
- stringbuffer buffer = new stringbuffer();
- buffer.append ("hello");
- }
- }
更正:為 stringbuffer 提供大小。
- public class rsbc {
- void method () {
- stringbuffer buffer = new stringbuffer(max);
- buffer.append ("hello");
- }
- private final int max = 100;
- }
19、不要總是使用取反操作符(!)
取反操作符(!)降低程序的可讀性,所以不要總是使用。
例子:
- public class dun {
- boolean method (boolean a, boolean b) {
- if (!a)
- return !a;
- else
- return !b;
- }
- }
更正:如果可能不要使用取反操作符(!)
20、與一個(gè)接口 進(jìn)行instanceof 操作
基于接口的設計通常是件好事,因為它允許有不同的實(shí)現,而又保持靈活。只要可能,對一個(gè)對象進(jìn)行 instanceof 操作,以判斷它是否某一接口要比是否某一個(gè)類(lèi)要快。
例子:
- public class insof {
- private void method (object o) {
- if (o instanceof interfacebase) { }
- if (o instanceof classbase) { }
- }
- }
-
- class classbase {}
- interface interfacebase {}
21、采用在需要的時(shí)候才開(kāi)始創(chuàng )建的策略。
例如:
- String str="abc";
- if(i==1){ list.add(str);}
應修改為: - if(i==1){String str="abc"; list.add(str);}
22、通過(guò) StringBuffer 的構造函數來(lái)設定他的初始化容量,可以明顯提升性能。
StringBuffer 的默認容量為 16,當 StringBuffer 的容量達到最大容量時(shí),她會(huì )將自身容量增加到當前的 2 倍+2,也就是 2*n+2。無(wú)論何時(shí),只要 StringBuffer 到達她的最大容量,她就不得不創(chuàng )建一個(gè)新的對象數組,然后復制舊的對象數組,這會(huì )浪費很多時(shí)間。所以給StringBuffer 設置一個(gè)合理的初始化容量值,是很有必要的!
Vector 與 StringBuffer 類(lèi)似,每次擴展容量時(shí),所有現有元素都要賦值到新的存儲空間中。Vector 的默認存儲能力為 10個(gè)元素,擴容加倍。 vector.add(index,obj) 這個(gè)方法可以將元素 obj 插入到index 位置,但 index 以及之后的元素依次都要向下移動(dòng)一個(gè)位置(將其索引加 1)。 除非必要,否則對性能不利。 同樣規則適用于 remove(int index)方法,移除此向量中指定位置的元素。將所有后續元素左移(將其索引減 1)。返回此向量中移除的元素。所以刪除 vector 最后一個(gè)元素要比刪除第1 個(gè)元素開(kāi)銷(xiāo)低很多。刪除所有元素最好用 removeAllElements()方法。 如果要刪除 vector 里的一個(gè)元素可以使用 vector.remove(obj);而不必自己檢索元素位置,再刪除,如 int index = indexOf(obj);vector.remove(index);
24、不要將數組聲明為:public static final
25、HaspMap 的遍歷
- Map<String, String[]> paraMap = new HashMap<String, String[]>();
- for( Entry<String, String[]> entry : paraMap.entrySet() )
- {
- String appFieldDefId = entry.getKey();
- String[] values = entry.getValue();
- }
利用散列值取出相應的 Entry 做比較得到結果,取得 entry的值之后直接取 key和 value。
26、array(數組)和 ArrayList 的使用。
array 數組效率最高,但容量固定,無(wú)法動(dòng)態(tài)改變,ArrayList 容量可以動(dòng)態(tài)增長(cháng),但犧牲了效率。
27、StringBuffer,StringBuilder 的區別
StringBuffer,StringBuilder 的區別在于:java.lang.StringBuffer 線(xiàn)程安全的可變字符序列。一個(gè)類(lèi)似于 String 的字符串緩沖區,但不能修改。StringBuilder 與該類(lèi)相比,通常應該優(yōu)先使用 StringBuilder 類(lèi),因為她支持所有相同的操作,但由于她不執行同步,所以速度更快。為了獲得更好的性能,在構造 StringBuffer 或 StringBuilder 時(shí)應盡量指定她的容量。當然如果不超過(guò) 16 個(gè)字符時(shí)就不用了。 相同情況下,使用 StringBuilder 比使用 StringBuffer 僅能獲得 10%~15%的性能提升,但卻要冒多線(xiàn)程不安全的風(fēng)險。綜合考慮還是建議使用 StringBuffer。
28、 盡量使用基本數據類(lèi)型代替對象。
29、用簡(jiǎn)單的數值計算代替復雜的函數計算,比如查表方式解決三角函數問(wèn)題。
30、使用具體類(lèi)比使用接口效率高,但結構彈性降低了,但現代 IDE 都可以解決這個(gè)問(wèn)題。
31、考慮使用靜態(tài)方法
如果你沒(méi)有必要去訪(fǎng)問(wèn)對象的外部,那么就使你的方法成為靜態(tài)方法。她會(huì )被更快地調用,因為她不需要一個(gè)虛擬函數導向表。這同事也是一個(gè)很好的實(shí)踐,因為她告訴你如何區分方法的性質(zhì),調用這個(gè)方法不會(huì )改變對象的狀態(tài)。
32.應盡可能避免使用內在的GET,SET 方法
android 編程中,虛方法的調用會(huì )產(chǎn)生很多代價(jià),比實(shí)例屬性查詢(xún)的代價(jià)還要多。我們應該在外包調用的時(shí)候才使用 get,set方法,但在內部調用的時(shí)候,應該直接調用。
33、避免枚舉,浮點(diǎn)數的使用。
34、二維數組比一維數組占用更多的內存空間,大概是 10 倍計算。
35、SQLite
SQLite 數據庫讀取整張表的全部數據很快,但有條件的查詢(xún)就要耗時(shí) 30-50MS,大家做這方面的時(shí)候要注意,盡量少用,尤其是嵌套查找!
36、奇偶判斷
不要使用 i % 2 == 1 來(lái)判斷是否是奇數,因為 i為負奇數時(shí)不成立,請使用 i % 2 != 0 來(lái)判斷是否是奇數,或使用 高效式 (i & 1) != 0 來(lái)判斷。