淺談:Java程式碼的最佳化策略

淺談:Java程式碼的最佳化策略

1。如何使用Exception

Exception降低效能。一個異常丟擲首先需要建立一個新的物件。 Throwable介面中的構造器呼叫名為fillInStackTrace()的本地方法。這個方法負責巡檢棧的整個框架來收集跟蹤資訊。這樣無論何時有異常丟擲,它要求虛擬機器裝載呼叫棧,因為一個新的對像在中部被建立。

異常應當僅用於有錯誤發生時,而不要控制流。

2。不要兩次初始化變數

Java透過呼叫獨特的類構造器預設地初始化變數為一個已知的值。所有的對像被設定成null,integers (byte, short, int, long)被設定成0,float和double設定成0。0,Boolean變數設定成false。這對那些擴充套件自其它類的類尤其重要,這跟使用一個新的關鍵詞建立一個物件時所有一連串的構造器被自動呼叫一樣。

3。在任何可能的地方讓類為Final

標記為final的類不能被擴充套件。在《核心Java API》中有大量這個技術的例子,諸如java。lang。String。將String類標記為final阻止了開發者建立他們自己實現的長度方法。

更深入點說,如果類是final的,所有類的方法也是final的。 Java編譯器可能會內聯所有的方法(這依賴於編譯器的實現)。在我的測試裡,我已經看到效能平均增加了50%。

4。在任何可能的地方使用區域性變數

屬於方法呼叫部分的自變數和宣告為此呼叫一部分的臨時變數儲存在棧中,這比較快。諸如static,例項(instance)變數和新的物件建立在堆中,這比較慢。區域性變數的更深入最佳化依賴於你正在使用的編譯器或虛擬機器。

5。停止小聰明

很多開發人員在腦子中編寫可複用和靈活的程式碼,而有時候在他們的程式中就產生額外的開銷。曾經或者另外的時候他們編寫了類似這樣的程式碼:

public void doSomething(File file) {

FileInputStream fileIn = new FileInputStream(file);

// do something

他夠靈活,但是同時他們也產生了更多的開銷。這個主意背後做的事情是操縱一個InputStream,而不是一個檔案,因此它應該重寫如下:

public void doSomething(InputStream inputStream){

// do something

6。乘法和除法

我有太多的東東適用於摩爾法則——它宣告CPU功率每年成倍增長。 “摩爾法則”表明每年由開發者所寫的差勁的程式碼數量三倍增加,劃去了摩爾法則的任何好處。

考慮下面的程式碼:

for (val = 0; val < 100000; val +=5) { shiftX = val 8; myRaise = val 2; }

如果我們狡猾的利用位移(bit),效能將會六倍增加。這是重寫的程式碼:

for (val = 0; val < 100000; val += 5) { shiftX = val << 3; myRaise = val << 1; }

代替了乘以8,我們使用同等效果的左移3位。每一個移動相當於乘以2,變數myRaise對此做了證明。同樣向右移位相當於除以2,當然這會使執行速度加快,但可能會使你的東東以後難於理解;所以這只是個建議

7。用程式碼有效處理記憶體溢位

OutOfMemoryError是由於記憶體不夠後普遍會遇到的問題,下面一段程式碼能有效判斷記憶體溢位錯誤,並在記憶體溢位發生時有效回收記憶體

透過該方法可以聯想到有效管理連線池溢位,道理等同。

import Java。util。*;

public class DataServer

{

private Hashtable data = new Hashtable();

public Object get (String key)

{

Object obj = data。get (key);

if (obj == null)

{

System。out。print (key + “ ”);

try

{

// simulate getting lots of data

obj = new Double[1000000];

data。put (key, obj);

}

catch (OutOfMemoryError e)

{

System。out。print (“No Memory! ”);

flushCache();

obj = get (key);// try again

}

}

return (obj);

}

public void flushCache()

{

System。out。println (“Clearing cache”);

data。clear();

}

public static void main (String[] args)

{

DataServer ds = new DataServer();

int count = 0;

while (true) // infinite loop for test

ds。get (“” count+);

}

}

8。 Lazy Loading (Lazy evaluation)在需要裝入的時候才裝入

static public long

factorial( int n ) throws IllegalArgumentException

{

IllegalArgumentException illegalArgumentException =

new IllegalArgumentException( “must be >= 0” );

if( n < 0 ) {

throw illegalArgumentException ;

} else if( ( n 0 ) || ( n 1 ) ) {

return( 1 );

} else (

return( n * factorial( n – 1 ) ) ;

}

最佳化後代碼

static public long

factorial( int n ) throws IllegalArgumentException

{

if( n < 0 ) {

throw new IllegalArgumentException( “must be >= 0” );

} else if( ( n 0 ) || ( n 1 ) ) {

return( 1 );

} else (

return( n * factorial( n – 1 ) ) ;

}

9。異常在需要丟擲的地方丟擲,try catch能整合就整合

try {

some。method1(); // Difficult for Javac

} catch( method1Exception e ) { // and the JVM runtime

// Handle exception 1 // to optimize this

} // code

try {

some。method2();

} catch( method2Exception e ) {

// Handle exception 2

}

try {

some。method3();

} catch( method3Exception e ) {

// Handle exception 3

}

已下程式碼更容易被編譯器最佳化

try {

some。method1(); // Easier to optimize

some。method2();

some。method3();

} catch( method1Exception e ) {

// Handle exception 1

} catch( method2Exception e ) {

// Handle exception 2

} catch( method3Exception e ) {

// Handle exception 3

}

10。 For迴圈的最佳化

Replace…

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

}

with…

for( int i = 0, n = collection。size(); i < n; i++ ) {

}

11。字串操作最佳化

在對字串實行+操作時,最好用一條語句

// Your source code looks like…

String str = “profit = revenue( ” revenue

“ – cost( ” cost ““;

//編譯方法

String str = new StringBuffer( )。append( “profit = revenue( “ )。

append( revenue )。append( “ – cost( “ )。

append( cost )。append( ““ )。toString( );

在迴圈中對字串操作時改用StringBuffer。append()方法

String sentence = “”;

for( int i = 0; i < wordArray。length; i++ ) {

sentence += wordArray[ i ];

}

最佳化為

StringBuffer buffer = new StringBuffer( 500 );

for( int i = 0; i < wordArray。length; i++ ) {

buffer。append( wordArray[ i ] );

}

String sentence = buffer。toString( );

12。物件重用(特別對於大物件來說)

public

class Point

{

public int x;

public int y;

public Point( )

{

this( 0, 0 );

}

}

最佳化為:

public class Component

{

private int x;

private int y;

public Point getPosition( )

{

Point rv = new Point( ); // Create a new Point

rv。x = x; // Update its state

rv。y = y;

return rv;

}

}

// Process an array of Component positions…

for( int i = 0; i < componentArray。length; i++ ) {

Point position = componentArray[i]。getPosition( );

// Process position value…

// Note: A Point object is created for each iteration

// of the loop…

}

可再次最佳化,僅使用一個類物件:)

public

class Component

{

private int x;

private int y;

public Point getPosition( Point rv )

{

if( rv == null) rv = new Point( );

rv。x = x; // Update its state

rv。y = y;

return rv;

}

// Create a single point object and reuse it…

Point p = new Point( );

for( int i = 0; i < componentArray。length; i++ ) {

Point position = componentArray[i]。getPosition