淺談: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( p );
// Process position value…
// Note: Only one Point object is ever created.
}

13. J2EE相關

a)盡量不要將大對象放到HttpSession或其他須序列化的對像中,並註意及時清空Session

b)使用預編譯語句prepareStatement代替createStatement

c)盡可能使用連接池

d)能使用Cache就使用Cache,具體實現可參考jive(CacheCacheableCacheObjectCacheSizesDefaultCacheLinkdListLinkdListNode)或ofbiz(org.ofbiz.core.util. UtilCache.Java)

This entry was posted in Java, SCJP, SUN.

发表评论

邮箱地址不会被公开。 必填项已用*标注


*

在线客服系统