java編碼優化10技巧的簡單介紹

本文目錄一覽:

北大青鳥java培訓:Java學習中代碼優化的方法有哪些?

每個人都說代碼是程序員手中的一把雕刻刀,是對他們產品輪廓和細節的打磨。

每個程序員在代碼優化方面需要做的是,即使是每天處理代碼的程序員也有很多關於他們編寫代碼的問題,所以優化很重要。

下面福建福建IT培訓為大家介紹代碼優化的方法。

1、盡量重用目標特別是,使用代表字元串收斂的String目標應該使用StringBuilder/StringBuffer。

因為Java虛擬機不僅要花時間生成目標,而且可能還需要花時間檢索和刪除這些目標,所以福建計算機學院發現生成太多目標會對程序的功能產生重大影響。

2、可以運用局部變數調用方法時傳遞的參數和調用中創建的臨時變數保存在堆棧中的速度更快。

其他變數,如靜態變數、實例變數等等,在堆中創建,速度較慢。

此外,福建北大青鳥發現在堆棧中創建的變數,方法的操作結束,當這些內容都消失了,就不需要額定廢物回收。

3、及時封閉流Java的程序編寫過程中,資料庫連接,I/O流操作必須謹慎,應用結束後,應該及時關閉發布資源。

因為福建java培訓發現這些大目標的運行會造成大系統支出,稍有不慎就會導致嚴重的結果。

如何優化JAVA程序設計和編碼,提高JAVA性能

通過使用一些輔助性工具來找到程序中的瓶頸,然後就可以對瓶頸部分的代碼進行優化。一般有兩種方案:即優化代碼或更改設計方法。我們一般會選擇後者,因為不去調用以下代碼要比調用一些優化的代碼更能提高程序的性能。而一個設計良好的程序能夠精簡代碼,從而提高性能。 下面將提供一些在JAVA程序的設計和編碼中,為了能夠提高JAVA程序的性能,而經常採用的一些方法和技巧。 1.對象的生成和大小的調整。 JAVA程序設計中一個普遍的問題就是沒有好好的利用JAVA語言本身提供的函數,從而常常會生成大量的對象(或實例)。由於系統不僅要花時間生成對象,以後可能還需花時間對這些對象進行垃圾回收和處理。因此,生成過多的對象將會給程序的性能帶來很大的影響。 例1:關於String,StringBuffer,+和append JAVA語言提供了對於String類型變數的操作。但如果使用不當,會給程序的性能帶來影響。如下面的語句: Stringname=newString(“HuangWeiFeng”);System.out.println(name+”ismyname”); 看似已經很精簡了,其實並非如此。為了生成二進位的代碼,要進行如下的步驟和操作: (1)生成新的字元串newString(STR_1);(2)複製該字元串; (3)載入字元串常量”HuangWeiFeng”(STR_2);(4)調用字元串的構架器(Constructor);(5)保存該字元串到數組中(從位置0開始); (6)從java.io.PrintStream類中得到靜態的out變數; (7)生成新的字元串緩衝變數newStringBuffer(STR_BUF_1);(8)複製該字元串緩衝變數; (9)調用字元串緩衝的構架器(Constructor);(10)保存該字元串緩衝到數組中(從位置1開始); (11)以STR_1為參數,調用字元串緩衝(StringBuffer)類中的append方法;(12)載入字元串常量”ismyname”(STR_3); (13)以STR_3為參數,調用字元串緩衝(StringBuffer)類中的append方法;(14)對於STR_BUF_1執行toString命令; (15)調用out變數中的println方法,輸出結果。 由此可以看出,這兩行簡單的代碼,就生成了STR_1,STR_2,STR_3,STR_4和STR_BUF_1五個對象變數。這些生成的類的實例一般都存放在堆中。堆要對所有類的超類,類的實例進行初始化,同時還要調用類極其每個超類的構架器。而這些操作都是非常消耗系統資源的。因此,對對象的生成進行限制,是完全有必要的。 經修改,上面的代碼可以用如下的代碼來替換。 StringBuffername=newStringBuffer(“HuangWeiFeng”); System.out.println(name.append(“ismyname.”).toString()); 系統將進行如下的操作: (1)生成新的字元串緩衝變數newStringBuffer(STR_BUF_1);(2)複製該字元串緩衝變數; (3)載入字元串常量”HuangWeiFeng”(STR_1);(4)調用字元串緩衝的構架器(Constructor);(5)保存該字元串緩衝到數組中(從位置1開始); (6)從java.io.PrintStream類中得到靜態的out變數;(7)載入STR_BUF_1; (8)載入字元串常量”ismyname”(STR_2); (9)以STR_2為參數,調用字元串緩衝(StringBuffer)實例中的append方法;(10)對於STR_BUF_1執行toString命令(STR_3);(11)調用out變數中的println方法,輸出結果。 由此可以看出,經過改進後的代碼只生成了四個對象變數:STR_1,STR_2,STR_3和STR_BUF_1.你可能覺得少生成一個對象不會對程序的性能有很大的提高。但下面的代碼段2的執行速度將是代碼段1的2倍。因為代碼段1生成了八個對象,而代碼段2隻生成了四個對象。 代碼段1: Stringname=newStringBuffer(“HuangWeiFeng”);name+=”ismy”;name+=”name”; 代碼段2: StringBuffername=newStringBuffer(“HuangWeiFeng”);name.append(“ismy”); name.append(“name.”).toString(); 因此,充分的利用JAVA提供的庫函數來優化程序,對提高JAVA程序的性能時非常重要的.其注意點主要有如下幾方面; (1)儘可能的使用靜態變數(StaticClassVariables)

如果類中的變數不會隨他的實例而變化,就可以定義為靜態變數,從而使他所有的實例都共享這個變數。 例: publicclassfoo{ SomeObjectso=newSomeObject();} 就可以定義為:publicclassfoo{ staticSomeObjectso=newSomeObject();} (2)不要對已生成的對象作過多的改變。 對於一些類(如:String類)來講,寧願在重新生成一個新的對象實例,而不應該修改已經生成的對象實例。例: Stringname=”Huang”;name=”Wei”;name=”Feng”; 上述代碼生成了三個String類型的對象實例。而前兩個馬上就需要系統進行垃圾回收處理。如果要對字元串進行連接的操作,性能將得更差,因為系統將不得為此生成更多得臨時變數,如上例1所示。 (3)生成對象時,要分配給它合理的空間和大小JAVA中的很多類都有它的默認的空間分配大小。對於StringBuffer類來講,默認的分配空間大小是16個字元。如果在程序中使用StringBuffer的空間大小不是16個字元,那麼就必須進行正確的初始化。 (4)避免生成不太使用或生命周期短的對象或變數。對於這種情況,因該定義一個對象緩衝池。以為管理一個對象緩衝池的開銷要比頻繁的生成和回收對象的開銷小的多。 (5)只在對象作用範圍內進行初始化。JAVA允許在代碼的任何地方定義和初始化對象。這樣,就可以只在對象作用的範圍內進行初始化。從而節約系統的開銷

Java代碼如何優化

1. 盡量在合適的場合使用單例

使用單例可以減輕載入的負擔,縮短載入的時間,提高載入的效率,但並不是所有地方都適用於單例,簡單來說,單例主要適用於以下三個方面:

第一,控制資源的使用,通過線程同步來控制資源的並發訪問;

第二,控制實例的產生,以達到節約資源的目的;

第三,控制數據共享,在不建立直接關聯的條件下,讓多個不相關的進程或線程之間實現通信。

2. 盡量避免隨意使用靜態變數

要知道,當某個對象被定義為stataic變數所引用,那麼gc通常是不會回收這個對象所佔有的內存

3. 盡量避免過多過常的創建Java對象

盡量避免在經常調用的方法,循環中new對象,由於系統不僅要花費時間來創建對象,而且還要花時間對這些對象進行垃圾回收和處理,在我們可以控制的範圍內,最大限度的重用對象,最好能用基本的數據類型或數組來替代對象。

4. 盡量使用final修飾符

帶有final修飾符的類是不可派生的。在Java核心API中,有許多應用final的例子,例如java.lang.String.為String類指定final防止了使用者覆蓋length()方法。另外,如果一個類是final的,則該類所有方法都是final的。Java編譯器會尋找機會內聯(inline)所有的final方法(這和具體的編譯器實現有關)。此舉能夠使性能平均提高50%.

5. 盡量使用局部變數

調用方法時傳遞的參數以及在調用中創建的臨時變數都保存在棧(Stack)中,速度較快。其他變數,如靜態變數、實例變數等,都在堆(Heap)中創建,速度較慢。

6. 盡量處理好包裝類型和基本類型兩者的使用場所

雖然包裝類型和基本類型在使用過程中是可以相互轉換,但它們兩者所產生的內存區域是完全不同的,基本類型數據產生和處理都在棧中處理,包裝類型是對象,是在堆中產生實例。

在集合類對象,有對象方面需要的處理適用包裝類型,其他的處理提倡使用基本類型。

7. 慎用synchronized,盡量減小synchronize的方法

都知道,實現同步是要很大的系統開銷作為代價的,甚至可能造成死鎖,所以盡量避免無謂的同步控制。synchronize方法被調用時,直接會把當前對象鎖 了,在方法執行完之前其他線程無法調用當前對象的其他方法。所以synchronize的方法盡量小,並且應盡量使用方法同步代替代碼塊同步。

8. 盡量使用StringBuilder和StringBuffer進行字元串連接

這個就不多講了。

9. 盡量不要使用finalize方法

實際上,將資源清理放在finalize方法中完成是非常不好的選擇,由於GC的工作量很大,尤其是回收Young代內存時,大都會引起應用程序暫停,所以再選擇使用finalize方法進行資源清理,會導致GC負擔更大,程序運行效率更差。

10. 盡量使用基本數據類型代替對象

String str = “hello”;

上面這種方式會創建一個”hello”字元串,而且JVM的字元緩存池還會緩存這個字元串;

String str = new String(“hello”);

此時程序除創建字元串外,str所引用的String對象底層還包含一個char[]數組,這個char[]數組依次存放了h,e,l,l,o

11. 單線程應盡量使用HashMap、ArrayList

HashTable、Vector等使用了同步機制,降低了性能。

12. 盡量合理的創建HashMap

當你要創建一個比較大的hashMap時,充分利用另一個構造函數

public HashMap(int initialCapacity, float loadFactor)

避免HashMap多次進行了hash重構,擴容是一件很耗費性能的事,在默認中initialCapacity只有16,而loadFactor是 0.75,需要多大的容量,你最好能準確的估計你所需要的最佳大小,同樣的Hashtable,Vectors也是一樣的道理。

13. 盡量減少對變數的重複計算

並且在循環中應該避免使用複雜的表達式,在循環中,循環條件會被反覆計算,如果不使用複雜表達式,而使循環條件值不變的話,程序將會運行的更快。

14. 盡量避免不必要的創建

15. 盡量在finally塊中釋放資源

程序中使用到的資源應當被釋放,以避免資源泄漏。這最好在finally塊中去做。不管程序執行的結果如何,finally塊總是會執行的,以確保資源的正確關閉。

16. 盡量使用移位來代替’a/b’的操作

“/”是一個代價很高的操作,使用移位的操作將會更快和更有效

17.盡量使用移位來代替’a*b’的操作

同樣的,對於’*’操作,使用移位的操作將會更快和更有效

18. 盡量確定StringBuffer的容量

StringBuffer 的構造器會創建一個默認大小(通常是16)的字元數組。在使用中,如果超出這個大小,就會重新分配內存,創建一個更大的數組,並將原先的數組複製過來,再 丟棄舊的數組。在大多數情況下,你可以在創建 StringBuffer的時候指定大小,這樣就避免了在容量不夠的時候自動增長,以提高性能。

19. 盡量早釋放無用對象的引用

大部分時,方法局部引用變數所引用的對象 會隨著方法結束而變成垃圾,因此,大部分時候程序無需將局部,引用變數顯式設為null.

20. 盡量避免使用二維數組

二維數據佔用的內存空間比一維數組多得多,大概10倍以上。

21. 盡量避免使用split

除非是必須的,否則應該避免使用split,split由於支持正則表達式,所以效率比較低,如果是頻繁的幾十,幾百萬的調用將會耗費大量資源,如果確實需 要頻繁的調用split,可以考慮使用apache的StringUtils.split(string,char),頻繁split的可以緩存結果。

22. ArrayList LinkedList

一 個是線性表,一個是鏈表,一句話,隨機查詢盡量使用ArrayList,ArrayList優於LinkedList,LinkedList還要移動指 針,添加刪除的操作LinkedList優於ArrayList,ArrayList還要移動數據,不過這是理論性分析,事實未必如此,重要的是理解好2 者得數據結構,對症下藥。

23. 盡量使用System.arraycopy ()代替通過來循環複製數組

System.arraycopy() 要比通過循環來複制數組快的多

24. 盡量緩存經常使用的對象

儘可能將經常使用的對象進行緩存,可以使用數組,或HashMap的容器來進行緩存,但這種方式可能導致系統佔用過多的緩存,性能下降,推薦可以使用一些第三方的開源工具,如EhCache,Oscache進行緩存,他們基本都實現了FIFO/FLU等緩存演算法。

25. 盡量避免非常大的內存分配

有時候問題不是由當時的堆狀態造成的,而是因為分配失敗造成的。分配的內存塊都必須是連續的,而隨著堆越來越滿,找到較大的連續塊越來越困難。

26. 慎用異常

當創建一個異常時,需要收集一個棧跟蹤(stack track),這個棧跟蹤用於描述異常是在何處創建的。構建這些棧跟蹤時需要為運行時棧做一份快照,正是這一部分開銷很大。當需要創建一個 Exception 時,JVM 不得不說:先別動,我想就您現在的樣子存一份快照,所以暫時停止入棧和出棧操作。棧跟蹤不只包含運行時棧中的一兩個元素,而是包含這個棧中的每一個元素。

如 果您創建一個 Exception ,就得付出代價。好在捕獲異常開銷不大,因此可以使用 try-catch 將核心內容包起來。從技術上講,您甚至可以隨意地拋出異常,而不用花費很大的代價。招致性能損失的並不是 throw 操作–儘管在沒有預先創建異常的情況下就拋出異常是有點不尋常。真正要花代價的是創建異常。幸運的是,好的編程習慣已教會我們,不應該不管三七二十一就 拋出異常。異常是為異常的情況而設計的,使用時也應該牢記這一原則。

(1)。 用Boolean.valueOf(boolean b)代替new Boolean()

包裝類的內存佔用是很恐怖的,它是基本類型內存佔用的N倍(N2),同時new一個對象也是性能的消耗。

(2)。 用Integer.valueOf(int i)代替new Integer()

和Boolean類似,java開發中使用Integer封裝int的場合也非常多,並且通常用int表示的數值都非常小。SUN SDK中對Integer的實例化進行了優化,Integer類緩存了-128到127這256個狀態的Integer,如果使用 Integer.valueOf(int i),傳入的int範圍正好在此內,就返回靜態實例。這樣如果我們使用Integer.valueOf代替new Integer的話也將大大降低內存的佔用。

(3)。 用StringBuffer的append方法代替”+”進行字元串相加。

這個已經被N多人說過N次了,這個就不多說了。

(4)。 避免過深的類層次結構和過深的方法調用。

因為這兩者都是非常佔用內存的(特別是方法調用更是堆棧空間的消耗大戶)。

(5)。 變數只有在用到它的時候才定義和實例化。

這是初學者最容易犯的錯,合理的使用變數,並且只有在用到它的時候才定義和實例化,能有效的避免內存空間和執行性能上的浪費,從而提高了代碼的效率。

(6)。 避免在循環體中聲明創建對象,即使該對象佔用內存空間不大。

這種情況在我們的實際應用中經常遇到,而且我們很容易犯類似的錯誤

採用上面的第二種編寫方式,僅在內存中保存一份對該對象的引用,而不像上面的第一種編寫方式中代碼會在內存中產生大量的對象引用,浪費大量的內存空間,而且增大了垃圾回收的負荷。因此在循環體中聲明創建對象的編寫方式應該盡量避免。

(7)。 如果if判斷中多個條件用’||’或者”連接,請將出現頻率最高的條件放在表達式最前面。

這個小技巧往往能有效的提高程序的性能,尤其是當if判斷放在循環體裡面時,效果更明顯。

1.JVM管理兩種類型的內存:堆內存(heap),棧內存(stack),堆內在主要用來存儲程序在運行時創建或實例化的對象與變數。而棧內存則是用來存儲程序代碼中聲明為靜態(static)(或非靜態)的方法。

2.JVM中對象的生命周期,創建階段,應用階段,不可視階段,不可到達階段,可收集階段,終結階段,釋放階段

3.避免在循環體中創建對象,即使該對象點用內存空間不大。

4.軟引用的主要特點是具有較強的引用功能。只有當內存不夠的時候,才回收這類內存,因此在內存足夠的時候,它們通常不被回收。它可以用於實現一些常用資源的緩存,實現Cache的功能

5.弱引用對象與Soft引用對象最大不同就在於:GC在進行回收時,需要通過演算法檢查是否回收Soft引用對象,而對於Weak引用對象,GC總是進行回收。

6.共享靜態變數存儲空間

7.有時候我們為了提高系統性能,避免重複耗時的操作,希望能夠重用一些創建完成的對象,利用對象池實現。類似JDBC連接池。

8.瞬間值,序列化對象大變數時,如果此大變數又沒有用途,則使用transient聲明,不序列化此變數。同時網路傳輸中也不傳輸。

9.不要提前創建對象

10 .(1)最基本的建議就是儘早釋放無用對象的引用

A a = new A();

a = null; //當使用對象a之後主動將其設置為空

(2)盡量少用finalize函數。

(3) 如果需要使用經常用到的圖片展,可以使用軟引用。

(4) 注意集合數據類型,包括數組,樹等數據,這些數據結構對GC來說,回收更為複雜,

(5) 盡量避免在類的默認構造器中創建,初始化大量的對象,防止在調用其自類的構造器時造成不必要的內存資源浪費。

(6) 盡量避免強制系統做垃圾內存回收。

(7) 盡量避免顯式申請數組空間。

(8) 盡量在合適的場景下使用對象池技術以提高系統性能,縮減系統內存開銷。

11.當做數組拷貝操作時,採用System.arraycopy()方法完成拷貝操作要比採用循環的辦法完成數組拷貝操作效率高

12. 盡量避免在循環體中調用方法,因為方法調用是比較昂貴的。

13. 盡量避免在循環體中使用try-catch 塊,最好在循環體外使用try–catch塊以提高系統性能。

14. 在多重循環中,如果有可能,盡量將最長的循環放在最內層,最短的循環放在最外層,以減少循環層間的變換次數。

15. 在需要線程安全的情況下,使用List list = Collections.synchronizedList(new ArrayList());

16. 如果預知長度,就設置ArrayList的長度。

17. ArrayList 與 LinkedList 選擇,熟悉底層的實現原理,選擇適當的容器。

18. 字元串累加採用StringBuffer.

19. 系統I/O優化,採用緩衝和壓縮技術。優化性能。

20. 避免在類在構造器的初始化其他類

21 盡量避免在構造中對靜態變數做賦值操作

22. 不要在類的構造器中創建類的實例

23. 組合優化繼承

24. 最好通過Class.forname() 動態的裝載類

25. JSP優化,採用out 對象中的print方法代替println()方法

26 .採用ServletOutputStream 對象代替JSPWriter對象

27. 採用適當的值初始化out 對象緩衝區的大小

28. 盡量採用forward()方法重定向新的JSP

29. 利用線程池技術處理客戶請求

30.Servlet優化

(1) 通過init()方法來緩存一些靜態數據以提高應用性能。

(2) 用print() 方法取代println()方法。

(3) 用ServletOutputStream 取代 PrintWriter.

(4) 盡量縮小同步代碼數量

31. 改善Servlet應用性能的方法

(1)不要使用SingleThreadModel

(2)使用線程池ThreadPool

32. EJB優化

實體EJB:

(1)實體EJB中常用數據緩存與釋放

(2)採用延遲載入的方式裝載關聯數據

(3)儘可能地應用CMP類型實體EJB

(4)直接採用JDBC技術處理大型數據

33. 優化JDBC連接

(1)設置合適的預取行值

(2)採用連接池技術

(3)全合理應用事務

(4)選擇合適的事務隔離層與及時關閉連接對象

34. PreparedStatemetn只編譯解析一次,而Statement每次都編譯解析。

35. 儘可能地做批處理更新

36. 通過採用合適的getXXX方法提高系統性能

37. 採用設計模式。

Java代碼優化有哪些常用的方法

1、 盡量指定類的final修飾符 帶有final修飾符的類是不可派生的。

在Java核心API中,有許多應用final的例子,例如java.lang.String。為String類指定final防止了人們覆蓋length()方法。另外,如果指定一個類為final,則該類所有的方法都是final。Java編譯器會尋找機會內聯(inline)所有的final方法(這和具體的編譯器實現有關)。此舉能夠使性能平均提高50% 。

2、 盡量重用對象。

特別是String 對象的使用中,出現字元串連接情況時應用StringBuffer 代替。由於系統不僅要花時間生成對象,以後可能還需花時間對這些對象進行垃圾回收和處理。因此,生成過多的對象將會給程序的性能帶來很大的影響。

3、 盡量使用局部變數,調用方法時傳遞的參數以及在調用中創建的臨時變數都保存在棧(Stack)中,速度較快。

其他變數,如靜態變數、實例變數等,都在堆(Heap)中創建,速度較慢。另外,依賴於具體的編譯器/JVM,局部變數還可能得到進一步優化。請參見《儘可能使用堆棧變數》。

4、 不要重複初始化變數

默認情況下,調用類的構造函數時, Java會把變數初始化成確定的值:所有的對象被設置成null,整數變數(byte、short、int、long)設置成0,float和double變數設置成0.0,邏輯值設置成false。當一個類從另一個類派生時,這一點尤其應該注意,因為用new關鍵詞創建一個對象時,構造函數鏈中的所有構造函數都會被自動調用。

5、 在JAVA + ORACLE 的應用系統開發中,java中內嵌的SQL語句盡量使用大寫的形式,以減輕ORACLE解析器的解析負擔。

6、 Java 編程過程中,進行資料庫連接、I/O流操作時務必小心,在使用完畢後,即使關閉以釋放資源。

因為對這些大對象的操作會造成系統大的開銷,稍有不慎,會導致嚴重的後果。

7、 由於JVM的有其自身的GC機制,不需要程序開發者的過多考慮,從一定程度上減輕了開發者負擔,但同時也遺漏了隱患,過分的創建對象會消耗系統的大量內存,嚴重時會導致內存泄露,因此,保證過期對象的及時回收具有重要意義。

JVM回收垃圾的條件是:對象不在被引用;然而,JVM的GC並非十分的機智,即使對象滿足了垃圾回收的條件也不一定會被立即回收。所以,建議我們在對象使用完畢,應手動置成null。

8、 在使用同步機制時,應盡量使用方法同步代替代碼塊同步。

9、 盡量減少對變數的重複計算

例如:for(int i = 0;i list.size; i ++) {

}

應替換為:

for(int i = 0,int len = list.size();i len; i ++){

}

10、盡量採用lazy loading 的策略,即在需要的時候才開始創建。

例如: String str = 「aaa」;

if(i == 1) {

list.add(str);

}

應替換為:

if(i == 1) {

String str = 「aaa」;

list.add(str);

}

11、慎用異常

異常對性能不利。拋出異常首先要創建一個新的對象。Throwable介面的構造函數調用名為fillInStackTrace()的本地(Native)方法,fillInStackTrace()方法檢查堆棧,收集調用跟蹤信息。只要有異常被拋出,VM就必須調整調用堆棧,因為在處理過程中創建了一個新的對象。 異常只能用於錯誤處理,不應該用來控制程序流程。

12、不要在循環中使用:

Try {

} catch() {

}

應把其放置在最外層。

13、StringBuffer 的使用:

StringBuffer表示了可變的、可寫的字元串。

有三個構造方法 :

StringBuffer (); //默認分配16個字元的空間

StringBuffer (int size); //分配size個字元的空間

StringBuffer (String str); //分配16個字元+str.length()個字元空間

你可以通過StringBuffer的構造函數來設定它的初始化容量,這樣可以明顯地提升性能。

這裡提到的構造函數是StringBuffer(int length),length參數表示當前的StringBuffer能保持的字元數量。你也可以使用ensureCapacity(int minimumcapacity)方法在StringBuffer對象創建之後設置它的容量。首先我們看看StringBuffer的預設行為,然後再找出一條更好的提升性能的途徑。

StringBuffer在內部維護一個字元數組,當你使用預設的構造函數來創建StringBuffer對象的時候,因為沒有設置初始化字元長度,StringBuffer的容量被初始化為16個字元,也就是說預設容量就是16個字元。當StringBuffer達到最大容量的時候,它會將自身容量增加到當前的2倍再加2,也就是(2*舊值+2)。如果你使用預設值,初始化之後接著往裡面追加字元,在你追加到第16個字元的時候它會將容量增加到34(2*16+2),當追加到34個字元的時候就會將容量增加到70(2*34+2)。無論何事只要StringBuffer到達它的最大容量它就不得不創建一個新的字元數組然後重新將舊字元和新字元都拷貝一遍――這也太昂貴了點。所以總是給StringBuffer設置一個合理的初始化容量值是錯不了的,這樣會帶來立竿見影的性能增益。StringBuffer初始化過程的調整的作用由此可見一斑。所以,使用一個合適的容量值來初始化StringBuffer永遠都是一個最佳的建議。

14、合理的使用Java類 java.util.Vector。

簡單地說,一個Vector就是一個java.lang.Object實例的數組。Vector與數組相似,它的元素可以通過整數形式的索引訪問。但是,Vector類型的對象在創建之後,對象的大小能夠根據元素的增加或者刪除而擴展、縮小。請考慮下面這個向Vector加入元素的例子:

Object bj = new Object();

Vector v = new Vector(100000);

for(int I=0;

I100000; I++) { v.add(0,obj); }

除非有絕對充足的理由要求每次都把新元素插入到Vector的前面,否則上面的代碼對性能不利。在默認構造函數中,Vector的初始存儲能力是10個元素,如果新元素加入時存儲能力不足,則以後存儲能力每次加倍。Vector類就對象StringBuffer類一樣,每次擴展存儲能力時,所有現有的元素都要複製到新的存儲空間之中。下面的代碼片段要比前面的例子快幾個數量級:

Object bj = new Object();

Vector v = new Vector(100000);

for(int I=0; I100000; I++) { v.add(obj); }

同樣的規則也適用於Vector類的remove()方法。由於Vector中各個元素之間不能含有「空隙」,刪除除最後一個元素之外的任意其他元素都導致被刪除元素之後的元素向前移動。也就是說,從Vector刪除最後一個元素要比刪除第一個元素「開銷」低好幾倍。

假設要從前面的Vector刪除所有元素,我們可以使用這種代碼:

for(int I=0; I100000; I++)

{

v.remove(0);

}

但是,與下面的代碼相比,前面的代碼要慢幾個數量級:

for(int I=0; I100000; I++)

{

v.remove(v.size()-1);

}

從Vector類型的對象v刪除所有元素的最好方法是:

v.removeAllElements();

假設Vector類型的對象v包含字元串「Hello」。考慮下面的代碼,它要從這個Vector中刪除「Hello」字元串:

String s = “Hello”;

int i = v.indexOf(s);

if(I != -1) v.remove(s);

這些代碼看起來沒什麼錯誤,但它同樣對性能不利。在這段代碼中,indexOf()方法對v進行順序搜索尋找字元串「Hello」,remove(s)方法也要進行同樣的順序搜索。改進之後的版本是:

String s = “Hello”;

int i = v.indexOf(s);

if(I != -1) v.remove(i);

這個版本中我們直接在remove()方法中給出待刪除元素的精確索引位置,從而避免了第二次搜索。一個更好的版本是:

String s = “Hello”; v.remove(s);

最後,我們再來看一個有關Vector類的代碼片段:

for(int I=0; I++;I v.length)

如果v包含100,000個元素,這個代碼片段將調用v.size()方法100,000次。雖然size方法是一個簡單的方法,但它仍舊需要一次方法調用的開銷,至少JVM需要為它配置以及清除堆棧環境。在這裡,for循環內部的代碼不會以任何方式修改Vector類型對象v的大小,因此上面的代碼最好改寫成下面這種形式:

int size = v.size(); for(int I=0; I++;Isize)

雖然這是一個簡單的改動,但它仍舊贏得了性能。畢竟,每一個CPU周期都是寶貴的。

15、當複製大量數據時,使用System.arraycopy()命令。

int[] src={1,3,5,6,7,8};

int[] dest = new int[6];

System.arraycopy(src, 0, dest, 0, 6);

src:源數組; srcPos:源數組要複製的起始位置;

dest:目的數組; destPos:目的數組放置的起始位置;

length:複製的長度.

注意:src and dest都必須是同類型或者可以進行轉換類型的數組.

16、代碼重構:增強代碼的可讀性。

public class ShopCart {

private List carts ;

public void add (Object item) {

if(carts == null) {

carts = new ArrayList();

}

crts.add(item);

}

public void remove(Object item) {

if(carts. contains(item)) {

carts.remove(item);

}

}

public List getCarts() {

//返回只讀列表

return Collections.unmodifiableList(carts);

}

//不推薦這種方式

//this.getCarts().add(item);

}

17、不用new關鍵詞創建類的實例

用new關鍵詞創建類的實例時,構造函數鏈中的所有構造函數都會被自動調用。但如果一個對象實現了Cloneable介面,我們可以調用它的clone()方法。clone()方法不會調用任何類構造函數。

在使用設計模式(Design Pattern)的場合,如果用Factory模式創建對象,則改用clone()方法創建新的對象實例非常簡單。例如,下面是Factory模式的一個典型實現:

public static Credit getNewCredit() {

return new Credit();

}

改進後的代碼使用clone()方法,如下所示:

private static Credit BaseCredit = new Credit();

public static Credit getNewCredit() {

return (Credit) BaseCredit.clone();

}

上面的思路對於數組處理同樣很有用。

18、乘法和除法

考慮下面的代碼:

for (val = 0; val 100000; val +=5) {

alterX = val * 8; myResult = val * 2;

}

用移位操作替代乘法操作可以極大地提高性能。下面是修改後的代碼:

for (val = 0; val 100000; val += 5) {

alterX = val 3; myResult = val 1;

}

修改後的代碼不再做乘以8的操作,而是改用等價的左移3位操作,每左移1位相當於乘以2。相應地,右移1位操作相當於除以2。值得一提的是,雖然移位操作速度快,但可能使代碼比較難於理解,所以最好加上一些注釋。

19、在JSP頁面中關閉無用的會話。

一個常見的誤解是以為session在有客戶端訪問時就被創建,然而事實是直到某server端程序調用HttpServletRequest.getSession(true)這樣的語句時才被創建,注意如果JSP沒有顯示的使用 關閉session,則JSP文件在編譯成Servlet時將會自動加上這樣一條語句HttpSession session = HttpServletRequest.getSession(true);這也是JSP中隱含的session對象的來歷。由於session會消耗內存資源,因此,如果不打算使用session,應該在所有的JSP中關閉它。

對於那些無需跟蹤會話狀態的頁面,關閉自動創建的會話可以節省一些資源。使用如下page指令:%@ page session=”false”%

20、JDBC與I/O

如果應用程序需要訪問一個規模很大的數據集,則應當考慮使用塊提取方式。默認情況下,JDBC每次提取32行數據。舉例來說,假設我們要遍歷一個5000行的記錄集,JDBC必須調用資料庫157次才能提取到全部數據。如果把塊大小改成512,則調用資料庫的次數將減少到10次。

21、Servlet與內存使用

許多開發者隨意地把大量信息保存到用戶會話之中。一些時候,保存在會話中的對象沒有及時地被垃圾回收機制回收。從性能上看,典型的癥狀是用戶感到系統周期性地變慢,卻又不能把原因歸於任何一個具體的組件。如果監視JVM的堆空間,它的表現是內存佔用不正常地大起大落。

解決這類內存問題主要有二種辦法。第一種辦法是,在所有作用範圍為會話的Bean中實現HttpSessionBindingListener介面。這樣,只要實現valueUnbound()方法,就可以顯式地釋放Bean使用的資源。

另外一種辦法就是儘快地把會話作廢。大多數應用伺服器都有設置會話作廢間隔時間的選項。另外,也可以用編程的方式調用會話的setMaxInactiveInterval()方法,該方法用來設定在作廢會話之前,Servlet容器允許的客戶請求的最大間隔時間,以秒計。

22、使用緩衝標記

一些應用伺服器加入了面向JSP的緩衝標記功能。例如,BEA的WebLogic Server從6.0版本開始支持這個功能,Open Symphony工程也同樣支持這個功能。JSP緩衝標記既能夠緩衝頁面片斷,也能夠緩衝整個頁面。當JSP頁面執行時,如果目標片斷已經在緩衝之中,則生成該片斷的代碼就不用再執行。頁面級緩衝捕獲對指定URL的請求,並緩衝整個結果頁面。對於購物籃、目錄以及門戶網站的主頁來說,這個功能極其有用。對於這類應用,頁面級緩衝能夠保存頁面執行的結果,供後繼請求使用。

23、選擇合適的引用機制

在典型的JSP應用系統中,頁頭、頁腳部分往往被抽取出來,然後根據需要引入頁頭、頁腳。當前,在JSP頁面中引入外部資源的方法主要有兩種:include指令,以及include動作。

include指令:例如%@ include file=”copyright.html” %。該指令在編譯時引入指定的資源。在編譯之前,帶有include指令的頁面和指定的資源被合併成一個文件。被引用的外部資源在編譯時就確定,比運行時才確定資源更高效。

include動作:例如jsp:include page=”copyright.jsp” /。該動作引入指定頁面執行後生成的結果。由於它在運行時完成,因此對輸出結果的控制更加靈活。但時,只有當被引用的內容頻繁地改變時,或者在對主頁面的請求沒有出現之前,被引用的頁面無法確定時,使用include動作才合算。

24、及時清除不再需要的會話

為了清除不再活動的會話,許多應用伺服器都有默認的會話超時時間,一般為30分鐘。當應用伺服器需要保存更多會話時,如果內存容量不足,操作系統會把部分內存數據轉移到磁碟,應用伺服器也可能根據「最近最頻繁使用」(Most Recently Used)演算法把部分不活躍的會話轉儲到磁碟,甚至可能拋出「內存不足」異常。在大規模系統中,串列化會話的代價是很昂貴的。當會話不再需要時,應當及時調用HttpSession.invalidate()方法清除會話。HttpSession.invalidate()方法通常可以在應用的退出頁面調用。

25、不要將數組聲明為:public static final 。

26、HashMap的遍歷效率討論

經常遇到對HashMap中的key和value值對的遍歷操作,有如下兩種方法:

MapString, String[] paraMap = new HashMapString, String[]();

//第一個循環

SetString appFieldDefIds = paraMap.keySet();

for (String appFieldDefId : appFieldDefIds) {

String[] values = paraMap.get(appFieldDefId);

……

}

//第二個循環

for(EntryString, String[] entry : paraMap.entrySet()){

String appFieldDefId = entry.getKey();

String[] values = entry.getValue();

…….

}

第一種實現明顯的效率不如第二種實現。

分析如下 SetString appFieldDefIds = paraMap.keySet(); 是先從HashMap中取得keySet

代碼如下:

public SetK keySet() {

SetK ks = keySet;

return (ks != null ? ks : (keySet = new KeySet()));

}

private class KeySet extends AbstractSetK {

public IteratorK iterator() {

return newKeyIterator();

}

public int size() {

return size;

}

public boolean contains(Object o) {

return containsKey(o);

}

public boolean remove(Object o) {

return HashMap.this.removeEntryForKey(o) != null;

}

public void clear() {

HashMap.this.clear();

}

}

其實就是返回一個私有類KeySet, 它是從AbstractSet繼承而來,實現了Set介面。

再來看看for/in循環的語法

for(declaration : expression)

statement

在執行階段被翻譯成如下各式

for(IteratorE #i = (expression).iterator(); #i.hashNext();){

declaration = #i.next();

statement

}

因此在第一個for語句for (String appFieldDefId : appFieldDefIds) 中調用了HashMap.keySet().iterator()

而這個方法調用了newKeyIterator()

IteratorK newKeyIterator() {

return new KeyIterator();

}

private class KeyIterator extends HashIteratorK {

public K next() {

return nextEntry().getKey();

}

}

所以在for中還是調用了

在第二個循環for(EntryString, String[] entry : paraMap.entrySet())中使用的Iterator是如下的一個內部

private class EntryIterator extends HashIteratorMap.EntryK,V {

public Map.EntryK,V next() {

return nextEntry();

}

}

此時第一個循環得到key,第二個循環得到HashMap的Entry效率就是從循環裡面體現出來的第二個循環此致可以直接取key和value值而第一個循環還是得再利用HashMap的get(Object key)來取value值現在看看HashMap的get(Object key)方法

public V get(Object key) {

Object k = maskNull(key);

int hash = hash(k);

int i = indexFor(hash, table.length); //Entry[] table

EntryK,V e = table;

while (true) {

if (e == null)

return null;

if (e.hash == hash eq(k, e.key))

return e.value;

e = e.next;

}

}

其實就是再次利用Hash值取出相應的Entry做比較得到結果,所以使用第一中循環相當於兩次進入HashMap的Entry

中而第二個循環取得Entry的值之後直接取key和value,效率比第一個循環高。其實按照Map的概念來看也應該是用第二個循環好一點,它本來就是key和value的值對,將key和value分開操作在這裡不是個好選擇。

27、array(數組) 和 ArryList的使用

array([]):最高效;但是其容量固定且無法動態改變;

ArrayList:容量可動態增長;但犧牲效率;

基於效率和類型檢驗,應儘可能使用array,無法確定數組大小時才使用ArrayList!

ArrayList是Array的複雜版本

ArrayList內部封裝了一個Object類型的數組,從一般的意義來說,它和數組沒有本質的差別,甚至於ArrayList的許多方法,如Index、IndexOf、Contains、Sort等都是在內部數組的基礎上直接調用Array的對應方法。

ArrayList存入對象時,拋棄類型信息,所有對象屏蔽為Object,編譯時不檢查類型,但是運行時會報錯。

註:jdk5中加入了對泛型的支持,已經可以在使用ArrayList時進行類型檢查。

從這一點上看來,ArrayList與數組的區別主要就是由於動態增容的效率問題了

28、盡量使用HashMap 和ArrayList ,除非必要,否則不推薦使用HashTable和Vector ,後者由於使用同步機制,而導致了性能的開銷。

29、StringBuffer 和StringBuilder的區別:

java.lang.StringBuffer線程安全的可變字元序列。一個類似於 String 的字元串緩衝區,但不能修改。

StringBuilder。與該類相比,通常應該優先使用 java.lang.StringBuilder類,因為它支持所有相同的操作,但由於它不執行同步,所以速度更快。為了獲得更好的性能,在構造 StirngBuffer 或 StirngBuilder 時應儘可能指定它的容量。當然,如果你操作的字元串長度不超過 16 個字元就不用了。 相同情況下使用 StirngBuilder 相比使用 StringBuffer 僅能獲得 10%-15% 左右的性能提升,但卻要冒多線程不安全的風險。而在現實的模塊化編程中,負責某一模塊的程序員不一定能清晰地判斷該模塊是否會放入多線程的環境中運行,因此:除非你能確定你的系統的瓶頸是在 StringBuffer 上,並且確定你的模塊不會運行在多線程模式下,否則還是用 StringBuffer 吧。

30、盡量避免使用split

除非是必須的,否則應該避免使用split,split由於支持正則表達式,所以效率比較低,如果是頻繁的幾十,幾百萬的調用將會耗費大量資源,如果確實需要頻繁的調用split,可以考慮使用apache的 StringUtils.split(string,char),頻繁split的可以緩存結果。

其他補充:

1、及時清除不再使用的對象,設為null

2、儘可能使用final,static等關鍵字

3、儘可能使用buffered對象

如何優化代碼使JAVA源文件及編譯後CLASS文件更小

1 盡量使用繼承,繼承的方法越多,你要寫的代碼量也就越少

2 打開JAVA編譯器的優化選項: javac -O 這個選項將刪除掉CLASS文件中的行號,並能把

一些private, static,final的小段方法申明為inline方法調用

3 把公用的代碼提取出來

4 不要初始化很大的數組,儘管初始化一個數組在JAVA代碼中只是一行的代碼量,但

編譯後的代碼是一行代碼插入一個數組的元素,所以如果你有大量的數據需要存在數組

中的話,可以先把這些數據放在String中,然後在運行期把字元串解析到數組中

5 日期類型的對象會佔用很大的空間,如果你要存儲大量的日期對象,可以考慮把它存儲為

long型,然後在使用的時候轉換為Date類型

6 類名,方法名和變數名盡量使用簡短的名字,可以考慮使用Hashjava, Jobe, Obfuscate and Jshrink等工具自動完成這個工作

7 將static final類型的變數定義到Interface中去

8 算術運算 能用左移/右移的運算就不要用*和/運算,相同的運算不要運算多次

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%。

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++ ) {

}

5、 在JAVA + ORACLE 的應用系統開發中,java中內嵌的SQL語句盡量使用大寫的形式,以減輕ORACLE解析器的解析負擔。

10、盡量採用lazy loading 的策略,即在需要的時候才開始創建。

例如: String str = 「aaa」;

if(i == 1) {

list.add(str);

}

應替換為:

if(i == 1) {

String str = 「aaa」;

list.add(str);

}

12、不要在循環中使用:

Try {

} catch() {

}

應把其放置在最外層

原創文章,作者:NPJJM,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/324972.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
NPJJM的頭像NPJJM
上一篇 2025-01-13 13:23
下一篇 2025-01-13 13:23

相關推薦

  • java client.getacsresponse 編譯報錯解決方法

    java client.getacsresponse 編譯報錯是Java編程過程中常見的錯誤,常見的原因是代碼的語法錯誤、類庫依賴問題和編譯環境的配置問題。下面將從多個方面進行分析…

    編程 2025-04-29
  • Java JsonPath 效率優化指南

    本篇文章將深入探討Java JsonPath的效率問題,並提供一些優化方案。 一、JsonPath 簡介 JsonPath是一個可用於從JSON數據中獲取信息的庫。它提供了一種DS…

    編程 2025-04-29
  • 使用vscode建立UML圖的實踐和技巧

    本文將重點介紹在使用vscode在軟體開發中如何建立UML圖,並且給出操作交互和技巧的指導。 一、概述 在軟體開發中,UML圖是必不可少的重要工具之一。它為軟體架構和各種設計模式的…

    編程 2025-04-29
  • Java騰訊雲音視頻對接

    本文旨在從多個方面詳細闡述Java騰訊雲音視頻對接,提供完整的代碼示例。 一、騰訊雲音視頻介紹 騰訊雲音視頻服務(Cloud Tencent Real-Time Communica…

    編程 2025-04-29
  • Java Bean載入過程

    Java Bean載入過程涉及到類載入器、反射機制和Java虛擬機的執行過程。在本文中,將從這三個方面詳細闡述Java Bean載入的過程。 一、類載入器 類載入器是Java虛擬機…

    編程 2025-04-29
  • Java Milvus SearchParam withoutFields用法介紹

    本文將詳細介紹Java Milvus SearchParam withoutFields的相關知識和用法。 一、什麼是Java Milvus SearchParam without…

    編程 2025-04-29
  • Java 8中某一周的周一

    Java 8是Java語言中的一個版本,於2014年3月18日發布。本文將從多個方面對Java 8中某一周的周一進行詳細的闡述。 一、數組處理 Java 8新特性之一是Stream…

    編程 2025-04-29
  • Python簡單數學計算

    本文將從多個方面介紹Python的簡單數學計算,包括基礎運算符、函數、庫以及實際應用場景。 一、基礎運算符 Python提供了基礎的算術運算符,包括加(+)、減(-)、乘(*)、除…

    編程 2025-04-29
  • Java判斷字元串是否存在多個

    本文將從以下幾個方面詳細闡述如何使用Java判斷一個字元串中是否存在多個指定字元: 一、字元串遍歷 字元串是Java編程中非常重要的一種數據類型。要判斷字元串中是否存在多個指定字元…

    編程 2025-04-29
  • Python滿天星代碼:讓編程變得更加簡單

    本文將從多個方面詳細闡述Python滿天星代碼,為大家介紹它的優點以及如何在編程中使用。無論是剛剛接觸編程還是資深程序員,都能從中獲得一定的收穫。 一、簡介 Python滿天星代碼…

    編程 2025-04-29

發表回復

登錄後才能評論