慎用異常
在java軟件開發中,經常使用try-catch進行錯誤捕獲異常,但是try-catch語句對系統性能而言是非常糟糕的,雖然再一次try-catch中無法察覺它帶來的損失,但是,一旦try-catch語句被應用於循環中,就會給系統帶來極大的傷害。
使用局部變量
調用方法時,傳遞的參數以及在調用中創建的臨時變量都保存在棧(Stack)中,速度較快。
其他變量,如靜態變量、實例變量等,都在堆(heap)創建速度較慢。
位運算代替乘除法
在所有運算中,位運算是最高效的運算。
一維數組代替二維數組
由於數組的隨機訪問非常好,許多JDK類庫,如ArrayList、Vector等都使用了數組作爲其底層實現,但是一維數組和二維數組的訪問速度是不一樣的,一維數組的訪問速度要優於二維數組。因此在性能敏感的系統中要使用二維數組的,可以通過可靠的算法,將二維數組轉爲一維數組在進行處理,以提高系統的響應速度。
二維數組定義:
int [ ][ ] arr=new int [5][3]; 表示五個一維數組,每個一維數組長度是3.這就組成了二維數組,即5行3列。
優化方式:把二維數組用一維數組替換,提取公共變量
這是一個二維數組
public class Demo {
public static void main(String[] args) throws Exception {
int array[][]=new int[10][5];
for(int i=0;i<array.length;i++) {
for(int j=0;j<array[0].length;j++){
array[i][j]=i;
}
}
}
}
把它變成等價的一維數組,並提取公共變量
public class Demo {
public static void main(String[] args) throws Exception {
int array[]=new int[50];
int len=array.length;
for(int i=0;i<len;i++) {
array[i]=i;
}
System.out.print(Arrays.toString(array));
}
}
優化完畢。
計算的時候我們也應該注意,提取重複的表達式、公因式等操作。
展開循環
普通的循環:
public class Demo {
public static void main(String[] args) throws Exception {
int arr[]=new int[10];
for(int i=0;i<10;i++) {
arr[i]=i;
}
System.out.println(Arrays.toString(arr));
}
}
結果:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
展開循環
public class Demo {
public static void main(String[] args) throws Exception {
int arr[]=new int[10];
for(int i=0;i<10;i+=2) {
arr[i]=i;
arr[i+1]=i+1;
}
System.out.println(Arrays.toString(arr));
}
}
結果:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
展開循環後,系統性能提升。效率提高。
使用arrayCopy
數組複製是一項使用頻率很高的功能,JDK中提供了一個高效的API來實現它
public static native void arraycopy(Object src, int srcPos,Object dest, int destPos,int length);
這個是System下的一個方法。
java本地方法,所以效率更高。以後數組複製就使用這個方法。(不要自己去實現)
public class Demo {
public static void main(String[] args) throws Exception {
long start=System.currentTimeMillis();
int arr[]=new int[1000000];
int arrs[]=new int[1000000];
for(int i=0;i<1000000;i+=2) {
arr[i]=i;
arr[i+1]=i+1;
}
for(int j=0;j<arr.length;j++) {
arrs[j]=arr[j];
}
System.out.println(System.currentTimeMillis()-start);
}
}
結果用時:9
public class Demo {
public static void main(String[] args) throws Exception {
long start=System.currentTimeMillis();
int arr[]=new int[1000000];
int arrs[]=new int[1000000];
for(int i=0;i<1000000;i+=2) {
arr[i]=i;
arr[i+1]=i+1;
}
System.arraycopy(arr, 0, arrs, 0, 1000000);
System.out.println(System.currentTimeMillis()-start);
}
}
結果用時:6
從結果可以看出小數據量就可以發現差距。所以用本地方法System.arraycopy來進行數組複製,
效率是最好的。
使用Buffer進行I/O操作
除了NIO之外,使用java進行I/O操作有兩種基本方式:
- 使用基於InputStream和OutputStream的方式
- 使用Writer和Reader
無論使用哪種方式進行文件I/O,如果能合理的使用緩衝,就能有效的提高I/O的性能,緩衝配套組件如下:
public class Demo {
public static void main(String[] args) throws Exception {
long start=System.currentTimeMillis();
String path="d:"+File.separator+"book.txt";
File file=new File(path);
FileOutputStream fos=new FileOutputStream(file);
DataOutputStream dos=new DataOutputStream(fos);
for(int i=0;i<10000;i++) {
dos.write(i);
}
dos.close();
fos.close();
System.out.println(System.currentTimeMillis()-start);
}
}
結果時長:168
public class Demo {
public static void main(String[] args) throws Exception {
long start=System.currentTimeMillis();
String path="d:"+File.separator+"book.txt";
File file=new File(path);
FileOutputStream fos=new FileOutputStream(file);
DataOutputStream dos=new DataOutputStream(new BufferedOutputStream(fos));
for(int i=0;i<10000;i++) {
dos.write(i);
}
dos.close();
fos.close();
System.out.println(System.currentTimeMillis()-start);
}
}
加上緩衝之後的時長:1
所以緩衝其實不論是在寫文件還是讀文件,對性能都有很大的提升。Reader和Writer的實例就不列舉了,
使用緩衝效果都很明顯。
使用clone()代替new
在java中新建對象實例最常用的方法是 使用new關鍵字,JDK對new關鍵字的支持非常好,使用new關鍵字創建輕量級對象時,速度非常快。但是對於重量級對象,由於對象在構造函數中可能會進行一些複雜且耗時的操作,因此構造函數的執行時間可能會比較長,同時也使得系統無法在短期內或得大量實例,這時,我們可以使用Object.clone()方法。
Object.clone()方法可以繞過對象構造函數,快速複製一個對象實例,由於不需要調用對象構造函數,因此clone方法不會受到構造函數的性能影響,所以快速生成一個實例,但是在默認情況下,clone()方法的生成只是原對象的淺拷貝,如果需要深拷貝,則需要重新實現clone方法。
靜態方法代替實例方法
使用static關鍵字描述的方法爲靜態方法。在java中由於實例方法需要維護一張類似虛函數表的結構,以實現對多態的支持。與靜態方法相比,實例方法的調用,需要更多的資源。因此對於常用的工具類,沒有對其進行重載的必要,那麼將它們聲明爲static,便可以加速方法的調用。
對於一些工具類,應該使用static方法實現,這樣不僅可以加快函數調用的速度,同時,調用static方法也不需要生成類的實例,比調用實例方法更爲方便、易用。