綜述
程序的性能受到代碼質(zhì)量的直接影響。本篇主要介紹一些代碼編寫(xiě)的小技巧和慣例。雖然看起來(lái)有些是微不足道的編程技巧,卻可能為系統(tǒng)性能帶來(lái)成倍的提升。
1 慎用異常
在Java開(kāi)發(fā)中,經(jīng)常使用try-catch進(jìn)行錯(cuò)誤捕獲,但是try-catch語(yǔ)句對(duì)系統(tǒng)性能而言是非常糟糕的。雖然一次try-catch中,無(wú)法察覺(jué)到它對(duì)性能帶來(lái)的損失,但是一旦try-catch語(yǔ)句被應(yīng)用于循環(huán)或是遍歷體內(nèi),就會(huì)給系統(tǒng)性能帶來(lái)極大的傷害。
劣:
@Test
public void test() {
long start = System.currentTimeMillis();
int a = 0;
for(int i=0;i<1000000000;i++){
try {
a++;
}catch (Exception e){
e.printStackTrace();
}
}
long useTime = System.currentTimeMillis()-start;
System.out.println("useTime:"+useTime);
}
運(yùn)行結(jié)果:useTime:10
將try-catch移到循環(huán)體外的代碼,那么性能就提升了將近一半。
優(yōu):
@Test
public void test(){
long start = System.currentTimeMillis();
int a = 0;
try {
for (int i=0;i<1000000000;i++){
a++;
}
}catch (Exception e){
e.printStackTrace();
}
long useTime = System.currentTimeMillis()-start;
System.out.println(useTime);
}
運(yùn)行結(jié)果:useTime:6
2 使用局部變量
調(diào)用方法時(shí)傳遞的參數(shù)以及在調(diào)用中創(chuàng)建的臨時(shí)變量都保存在棧(Stack)中,速度快。其他變量,如靜態(tài)變量、實(shí)例變量等,都在堆(Heap)中創(chuàng)建,速度較慢。
劣:
static int aa = 0;
@Test
public void test(){
long start = System.currentTimeMillis();
for (int i=0;i<1000000000;i++){
aa++;
}
long useTime = System.currentTimeMillis()-start;
System.out.println("useTime:"+useTime);
}
運(yùn)行結(jié)果:useTime:90
將類(lèi)的靜態(tài)變量替換為局部變量:
優(yōu):
@Test
public void test() {
long start = System.currentTimeMillis();
int a = 0;
for(int i=0;i<1000000000;i++){
a++;
}
long useTime = System.currentTimeMillis()-start;
System.out.println("useTime:"+useTime);
}
運(yùn)行結(jié)果:useTime:6
3 位運(yùn)算代替乘除法
在所有的運(yùn)算中,位運(yùn)算是最為高效的。因此,可以嘗試使用位運(yùn)算代替部分算術(shù)運(yùn)算,來(lái)提高系統(tǒng)的運(yùn)行速度。最典型的就是對(duì)于整數(shù)的乘除運(yùn)算優(yōu)化。
劣:
@Test
public void test() {
long start = System.currentTimeMillis();
int a = 0;
for(int i=0;i<1000000000;i++){
a*=2;
a/=2;
}
long useTime = System.currentTimeMillis()-start;
System.out.println("useTime:"+useTime);
}
運(yùn)行結(jié)果:useTime:1329
將循環(huán)體中的乘除運(yùn)算改為等價(jià)的位運(yùn)算。
優(yōu):
@Test
public void test(){
long start = System.currentTimeMillis();
int aa = 0;
for (int i=0;i<1000000000;i++){
aa<<=1;
aa>>=1;
}
long useTime = System.currentTimeMillis()-start;
System.out.println("useTime:"+useTime);
}
運(yùn)行結(jié)果:useTime:9
4 提取表達(dá)式
在軟件開(kāi)發(fā)過(guò)程中,程序員很容易有意無(wú)意地讓代碼做一些“重復(fù)勞動(dòng)”,在大部分情況下,由于計(jì)算機(jī)的高速運(yùn)行,這些“重復(fù)勞動(dòng)”并不會(huì)對(duì)性能構(gòu)成太大的威脅,但若希望將系統(tǒng)性能發(fā)揮到極致,提取這些“重復(fù)勞動(dòng)”相當(dāng)有意義。
劣:
@Test
public void testExpression(){
long start = System.currentTimeMillis();
double d = Math.random();
double a = Math.random();
double b = Math.random();
double e = Math.random();
double x,y;
for(int i=0;i<10000000;i++){
x = d*a*b/3*4*a;
y = e*a*b/3*4*a;
}
long useTime = System.currentTimeMillis()-start;
System.out.println("useTime:"+useTime);
}
運(yùn)行結(jié)果:useTime:21
兩個(gè)計(jì)算表達(dá)式的后半部分完全相同,這也意味著在每次循環(huán)中,相同部分的表達(dá)式被重新計(jì)算了。
優(yōu):
@Test
public void testExpression99(){
long start = System.currentTimeMillis();
double d = Math.random();
double a = Math.random();
double b = Math.random();
double e = Math.random();
double p,x,y;
for(int i=0;i<10000000;i++){
p = a*b/3*4*a;
x = d*p;
y = e*p;
}
long useTime = System.currentTimeMillis()-start;
System.out.println("useTime:"+useTime);
}
運(yùn)行結(jié)果:useTime:10
5 使用arrayCopy()
數(shù)組復(fù)制是一項(xiàng)使用頻率很高的功能,JDK中提供了一個(gè)高效的API來(lái)實(shí)現(xiàn)它。
例:
@Test
public void testArrayCopy(){
int size = 100000;
int[] array = new int[size];
int[] arraydest = new int[size];
for(int i=0;i<array.length;i++){
array[i] = i;
}
long start = System.currentTimeMillis();
for (int k=0;k<1000;k++){
//進(jìn)行復(fù)制
System.arraycopy(array,0,arraydest,0,size);
}
long useTime = System.currentTimeMillis()-start;
System.out.println("useTime:"+useTime);
}
6 使用Buffer進(jìn)行I/O操作
除NIO外,使用Java進(jìn)行I/O操作有兩種基本方式;
使用基于InpuStream和OutputStream的方式;
使用Writer和Reader;
無(wú)論使用哪種方式進(jìn)行文件I/O,如果能合理地使用緩沖,就能有效地提高I/O的性能。
InputStream、OutputStream、Writer和Reader配套使用的緩沖組件。