1. 程式人生 > >Java高手:提高Java效能的十一個習慣用法

Java高手:提高Java效能的十一個習慣用法

Java語言習慣用語

1。迴圈

■ 在重要的迴圈裡,消除迴圈終止判斷時的方法呼叫。

例如:將

for(int i=0; i<collection.size();i++){ ... }

替換為…

for(int i=0; n=collection.size();i<n;i++){...}

■ 通常,把與迴圈index不相關的移到迴圈的外面

for(int i=0; terminal=x.length;i<terminal;i++){x[i] = x[i]/scaleA *scaleB;}

應該該成:

Double scale = scaleB*scaleA;for(int i=0; terminal=x.length;i<terminal;i++){x[i] = x[i]/scale ;}

2。字串

■ 消除字串連線

■ 建立長字串時,總是使用StringBuffter代替String

■ 預先分配StringBuffer空間 StringBuffer sb = new StringBuffer(5000);

3。基本資料型別

■ 在重要的迴圈裡使用基本資料型別(int型資料通常比long/double型資料更快)

■ 基本資料型別(Boolean,Integer,etc)的包裝類主要用在當傳遞的方法引數必須是一個物件的引用時(而不是一個基本資料型別)

■ 對所有的常量代數表示式使用static final修飾符

■ 使常量更容易引用(編譯器預先計算常量表達式)

4。異常

■ 異常只用於單個真正的錯誤條件 如小說520網 www.5a520.cn 丟擲異常時

丟擲一個異常和執行一個catch程式碼塊花費是很高的(主要由於當建立一個異常時要獲得執行緒棧的一個快照)

只當條件真的異常時才丟擲一個異常

■ 丟擲異常首先要建立一個新的物件。

Throwable介面的建構函式呼叫名為fillInStackTrace()的本地(Native)方法,fillInStackTrace()方法檢查堆疊,收集呼叫跟蹤資訊。

只要有異常被丟擲,VM就必須調整呼叫堆疊,因為在處理過程中建立了一個新的物件。

異常只能用於錯誤處理,不應該用來控制程式流程。

■ 使編譯器和執行時最優化,將幾個方法呼叫放在一個try/catch塊中,而不是為每個方法呼叫實現幾個try/catch塊

try{ Some.method1(); //Difficut for java1.4 }catch(method1Exception e){ handle exception 1 // to optimize this code } try{ Some.method2(); //Difficut for java1.4 }catch(method2Exception e){ handle exception 2 // to optimize this code } try{ Some.method3(); //Difficut for java1.4 }catch(method3Exception e){ handle exception 3 // to optimize this code }

應該寫為:

try{ Some.method1(); Some.method2(); Some.method3(); //Difficut for java1.4 }catch(method1Exception e){ handle exception 1 }catch(method2Exception e){ handle exception 2 }catch(method3Exception e){ handle exception 3 }

5。基準

■ 注意,所有這些技巧會因不同的平臺和虛擬機器而不同

一 例如:在有些servlet容器內,通過一個OutputStream作為位元組輸出會更快

二 在其它的容器內,通過一個PrintWriter輸出字元會更快

■ 這些技巧描述的是最可移植的建議

■ 你可能需要執行一些基準來判斷在你的平臺上怎麼樣是最快的

6。不用new關鍵詞建立類的例項

■用new關鍵詞建立類的例項時,建構函式鏈中的所有建構函式都會被自動呼叫。

但如果一個物件實現了Cloneable介面,我們可以呼叫它的clone()方法。clone()方法不會呼叫任何類建構函式。

在使用設計模式(Design Pattern)的場合,如果用Factory模式建立物件,則改用clone()方法建立新的物件例項非常簡單。

例如,下面是Factory模式的一個典型實現:

public static Credit getNewCredit() { return new Credit(); }

優化後:

private static Credit BaseCredit = new Credit(); public static Credit getNewCredit() { return (Credit) BaseCredit.clone();}

上面的思路對於陣列處理同樣很有用。

7。使用非阻塞I/O

■Java版本較低的JDK不支援非阻塞I/O API。為避免I/O阻塞,一些應用採用了建立大量執行緒的辦法(在較好的情況下,會使用一個緩衝池)。這種技術可以在許多必須支援併發I/O流的應用中見 到,如Web伺服器、報價和拍賣應用等。然而,建立Java執行緒需要相當可觀的開銷。

JDK 1.4引入了非阻塞的I/O庫(java.nio)。如果應用要求使用版本較早的JDK,在這裡有一個支援非阻塞I/O的軟體包。

8。不要重複初始化變數

■預設情況下,呼叫類的建構函式時, Java會把變數初始化成確定的值:所有的物件被設定成null,整數變數(byte、short、int、long)設定成0,float和 double變數設定成0.0,邏輯值設定成false。

當一個類從另一個類派生時,這一點尤其應該注意,因為用new關鍵詞建立一個物件時,建構函式鏈中的所有建構函式都會被自動呼叫。

9。儘量指定類的final修飾符

■帶有final修飾符的類是不可派生的。在Java核心API中,有許多應用final的例子,例如java.lang.String。為String類指定final防止了人們覆蓋length()方法。

另外,如果指定一個類為final,則該類所有的方法都是final。Java編譯器會尋找機會內聯(inline)所有的final方法(這和具體的編譯器實現有關)。此舉能夠使效能平均提高50%。

10。儘量使用區域性變數

■呼叫方法時傳遞的引數以及在呼叫中建立的臨時變數都儲存在棧(Stack)中,速度較快。其他變數,如靜態變數、例項變數等,都在堆(Heap)中建立,速度較慢。另外,依賴於具體的編譯器/JVM,區域性變數還可能得到進一步優化。請參見《儘可能使用堆疊變數》。

11。乘法和除法

■考慮下面的程式碼:

for (val = 0; val < 100000; val +=5) { alterX = val * 8; myResult = val * 2; }

優化後:

for (val = 0; val < 100000; val += 5) { alterX = val << 3; myResult = val << 1; }

修改後的程式碼不再做乘以8的操作,而是改用等價的左移3位操作,每左移1位相當於乘以2。相應地,右移1位操作相當於除以2。值得一提的是,雖然移位操作速度快,但可能使程式碼比較難於理解,所以最好加上一些註釋。