后端技术:Java代码优秀案例,一定对你有提升!
程序的性能受到代碼質量的直接影響。今天給大家主要介紹一些代碼編寫的小技巧和慣例。雖然看起來有些是微不足道的編程技巧,卻可能為系統性能帶來成倍的提升,因此還是值得關注的。
1、慎用異常
在Java開發中,經常使用try-catch進行錯誤捕獲,但是try-catch語句對系統性能而言是非常糟糕的。雖然一次try-catch中,無法察覺到她對性能帶來的損失,但是一旦try-catch語句被應用于循環或是遍歷體內,就會給系統性能帶來極大的傷害。
以下是一段將try-catch應用于循環體內的示例代碼:
@Testpublic?void?test11()?{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);}上面這段代碼運行結果是:
useTime:10
下面是一段將try-catch移到循環體外的代碼,那么性能就提升了將近一半。如下:
@Testpublic?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);}運行結果:
useTime:6
2、使用局部變量
調用方法時傳遞的參數以及在調用中創建的臨時變量都保存在棧(Stack)中,速度快。其他變量,如靜態變量、實例變量等,都在堆(Heap)中創建,速度較慢。
下面是一段使用局部變量進行計算的代碼:
@Testpublic?void?test11()?{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);}運行結果:
useTime:5
將局部變量替換為類的靜態變量:
static?int?aa?=?0;@Testpublic?void?test(){long?start?=?System.currentTimeMillis();for?(int?i=0;i<1000000000;i++){aa++;}long?useTime?=?System.currentTimeMillis()-start;System.out.println("useTime:"+useTime);}運行結果:
useTime:94
通過上面兩次的運行結果,可以看出來局部變量的訪問速度遠遠高于類成員變量。
3、位運算代替乘除法
在所有的運算中,位運算是最為高效的。因此,可以嘗試使用位運算代替部分算術運算,來提高系統的運行速度。最典型的就是對于整數的乘除運算優化。
下面是一段使用算術運算的代碼:
@Testpublic?void?test11()?{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);}運行結果:
useTime:1451
將循環體中的乘除運算改為等價的位運算,代碼如下:
@Testpublic?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);}運行結果:
useTime:10
上兩段代碼執行了完全相同的功能,在每次循環中,都將整數乘以2,并除以2。但是運行結果耗時相差非常大,所以位運算的效率還是顯而易見的。
4、提取表達式
在軟件開發過程中,程序員很容易有意無意地讓代碼做一些“重復勞動”,在大部分情況下,由于計算機的高速運行,這些“重復勞動”并不會對性能構成太大的威脅,但若希望將系統性能發揮到極致,提取這些“重復勞動”相當有意義。
比如以下代碼中進行了兩次算術計算:
@Testpublic?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);}運行結果:
useTime:21
仔細看能發現,兩個計算表達式的后半部分完全相同,這也意味著在每次循環中,相同部分的表達式被重新計算了。
那么改進一下后就變成了下面的樣子:
@Testpublic?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);}運行結果:
useTime:11
通過運行結果我們可以看出來具體的優化效果。
同理,如果在某循環中需要執行一個耗時操作,而在循環體內,其執行結果總是唯一的,也應該提取到循環體外。
例如下面的代碼:
for(int?i=0;i<100000;i++){x[i]?=?Math.PI*Math.sin(y)*i; }應該改進成下面的代碼:
//提取復雜,固定結果的業務邏輯處理到循環體外 double?p?=?Math.PI*Math.sin(y); for(int?i=0;i<100000;i++){x[i]?=?p*i; }5、使用arrayCopy()
數組復制是一項使用頻率很高的功能,JDK中提供了一個高效的API來實現它。
/***?@param??????src??????the?source?array.*?@param??????srcPos???starting?position?in?the?source?array.*?@param??????dest?????the?destination?array.*?@param??????destPos??starting?position?in?the?destination?data.*?@param??????length???the?number?of?array?elements?to?be?copied.*?@exception??IndexOutOfBoundsException??if?copying?would?cause*???????????????access?of?data?outside?array?bounds.*?@exception??ArrayStoreException??if?an?element?in?the?<code>src</code>*???????????????array?could?not?be?stored?into?the?<code>dest</code>?array*???????????????because?of?a?type?mismatch.*?@exception??NullPointerException?if?either?<code>src</code>?or*???????????????<code>dest</code>?is?<code>null</code>.*/public?static?native?void?arraycopy(Object?src,??int??srcPos,Object?dest,?int?destPos,int?length);如果在應用程序中需要進行數組復制,應該使用這個函數,而不是自己實現。
下面來舉例:
@Testpublic?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++){//進行復制System.arraycopy(array,0,arraydest,0,size);}long?useTime?=?System.currentTimeMillis()-start;System.out.println("useTime:"+useTime);}運行結果:
useTime:59
相對應地,如果在程序中,自己實現數組復制,其等價代碼如下:
@Testpublic?void?testArrayCopy99(){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++){for(int?i=0;i<size;i++){arraydest[i]?=?array[i];}}long?useTime?=?System.currentTimeMillis()-start;System.out.println("useTime:"+useTime);}運行結果:
useTime:102
通過運行結果可以看出效果。
因為System.arraycopy()函數是native函數,通常native函數的性能要優于普通函數。僅出于性能考慮,在程序開發時,應盡可能調用native函數。
6、使用Buffer進行I/O操作
除NIO外,使用Java進行I/O操作有兩種基本方式;
使用基于InpuStream和OutputStream的方式;
使用Writer和Reader;
無論使用哪種方式進行文件I/O,如果能合理地使用緩沖,就能有效地提高I/O的性能。
InputStream、OutputStream、Writer和Reader配套使用的緩沖組件。
如下圖:
使用緩沖組件對文件I/O進行包裝,可以有效提升文件I/O的性能。
下面是一個直接使用InputStream和OutputStream進行文件讀寫的代碼:
@Testpublic?void?testOutAndInputStream(){try?{DataOutputStream?dataOutputStream?=?new?DataOutputStream(new?FileOutputStream("/IdeaProjects/client2/src/test/java/com/client2/cnblogtest/teststream.txt"));long?start?=?System.currentTimeMillis();for(int?i=0;i<10000;i++){dataOutputStream.writeBytes(Objects.toString(i)+"\r\n");}dataOutputStream.close();long?useTime?=?System.currentTimeMillis()-start;System.out.println("寫入數據--useTime:"+useTime);//開始讀取數據long?startInput?=?System.currentTimeMillis();DataInputStream?dataInputStream?=?new?DataInputStream(new?FileInputStream("/IdeaProjects/client2/src/test/java/com/client2/cnblogtest/teststream.txt"));while?(dataInputStream.readLine()?!=?null){}dataInputStream.close();long?useTimeInput?=?System.currentTimeMillis()-startInput;System.out.println("讀取數據--useTimeInput:"+useTimeInput);}catch?(Exception?e){e.printStackTrace();}}運行結果:
寫入數據--useTime:660
讀取數據--useTimeInput:274
使用緩沖的代碼如下:
@Testpublic?void?testBufferedStream(){try?{DataOutputStream?dataOutputStream?=?new?DataOutputStream(new?BufferedOutputStream(new?FileOutputStream("/IdeaProjects/client2/src/test/java/com/client2/cnblogtest/teststream.txt")));long?start?=?System.currentTimeMillis();for(int?i=0;i<10000;i++){dataOutputStream.writeBytes(Objects.toString(i)+"\r\n");}dataOutputStream.close();long?useTime?=?System.currentTimeMillis()-start;System.out.println("寫入數據--useTime:"+useTime);//開始讀取數據long?startInput?=?System.currentTimeMillis();DataInputStream?dataInputStream?=?new?DataInputStream(new?BufferedInputStream(new?FileInputStream("/IdeaProjects/client2/src/test/java/com/client2/cnblogtest/teststream.txt")));while?(dataInputStream.readLine()?!=?null){}dataInputStream.close();long?useTimeInput?=?System.currentTimeMillis()-startInput;System.out.println("讀取數據--useTimeInput:"+useTimeInput);}catch?(Exception?e){e.printStackTrace();}}運行結果:
寫入數據--useTime:22
讀取數據--useTimeInput:12
通過運行結果,我們能很明顯的看出來使用緩沖的代碼,無論在讀取還是寫入文件上,性能都有了數量級的提升。
使用Wirter和Reader也有類似的效果。
如下代碼:
@Testpublic?void?testWriterAndReader(){try?{long?start?=?System.currentTimeMillis();FileWriter?fileWriter?=?new?FileWriter("/IdeaProjects/client2/src/test/java/com/client2/cnblogtest/teststream.txt");for?(int?i=0;i<100000;i++){fileWriter.write(Objects.toString(i)+"\r\n");}fileWriter.close();long?useTime?=?System.currentTimeMillis()-start;System.out.println("寫入數據--useTime:"+useTime);//開始讀取數據long?startReader?=?System.currentTimeMillis();FileReader?fileReader?=?new?FileReader("/IdeaProjects/client2/src/test/java/com/client2/cnblogtest/teststream.txt");while?(fileReader.read()?!=?-1){}fileReader.close();long?useTimeInput?=?System.currentTimeMillis()-startReader;System.out.println("讀取數據--useTimeInput:"+useTimeInput);}catch?(Exception?e){e.printStackTrace();}}運行結果:
寫入數據--useTime:221
讀取數據--useTimeInput:147
對應的使用緩沖的代碼:
@Testpublic?void?testBufferedWriterAndReader(){try?{long?start?=?System.currentTimeMillis();BufferedWriter?fileWriter?=?new?BufferedWriter(new?FileWriter("/IdeaProjects/client2/src/test/java/com/client2/cnblogtest/teststream.txt"));for?(int?i=0;i<100000;i++){fileWriter.write(Objects.toString(i)+"\r\n");}fileWriter.close();long?useTime?=?System.currentTimeMillis()-start;System.out.println("寫入數據--useTime:"+useTime);//開始讀取數據long?startReader?=?System.currentTimeMillis();BufferedReader?fileReader?=?new?BufferedReader(new?FileReader("/IdeaProjects/client2/src/test/java/com/client2/cnblogtest/teststream.txt"));while?(fileReader.read()?!=?-1){}fileReader.close();long?useTimeInput?=?System.currentTimeMillis()-startReader;System.out.println("讀取數據--useTimeInput:"+useTimeInput);}catch?(Exception?e){e.printStackTrace();}}運行結果:
寫入數據--useTime:157
讀取數據--useTimeInput:59
通過運行結果可以看出,使用了緩沖后,無論是FileReader還是FileWriter的性能都有較為明顯的提升。
在上面的例子中,由于FileReader和FilerWriter的性能要優于直接使用FileInputStream和FileOutputStream所以循環次數增加了10倍。
IT技術分享社區
個人博客網站:https://programmerblog.xyz
文章推薦程序員效率:畫流程圖常用的工具程序員效率:整理常用的在線筆記軟件遠程辦公:常用的遠程協助軟件,你都知道嗎?51單片機程序下載、ISP及串口基礎知識硬件:斷路器、接觸器、繼電器基礎知識
總結
以上是生活随笔為你收集整理的后端技术:Java代码优秀案例,一定对你有提升!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SpringBoot + iframe
- 下一篇: google 确定某点海拔高_“湘能楚天