就像鯨魚吃蝦米一樣,也許吃一個兩個蝦米對於鯨魚來說作用不大,但是吃的蝦米多了,鯨魚自然飽了。
代碼最佳化一樣,也許一個兩個的最佳化,對於提升代碼的運行效率意義不大,但是只要處處都能注意代碼最佳化,總體來說對於提升代碼的運行效率就很有用了。
這個觀點,在現在看來,是要進行代碼最佳化的一個原因,但不全對。在機械工藝發展的今天,伺服器動輒8核、16核,64位CPU,代碼執行效率非常高,StringBuilder替換StringBuffer、ArrayList替換Vector,對於代碼運行效率的提升是微乎其微的,即使是項目中的每個點都注意到了,代碼運行也看不出什麼明顯的變化。
我認為,代碼最佳化的最重要的作用應該是:避免未知的錯誤。
在代碼上線啟動並執行過程中,往往會出現很多我們意想不到的錯誤,因為線上環境和開發環境是非常不同的,錯誤定位到最後往往是一個非常小的原因。然而為瞭解決這個錯誤,我們需要先自驗證、再打包出待替換的class檔案、暫停業務並重啟,對於一個成熟的項目而言,最後一條其實影響是非常大的,這意味著這段時間使用者無法訪問應用。
因此,在寫代碼的時候,從源頭開始注意各種細節,權衡並使用最優的選擇,將會很大程度上避免出現未知的錯誤,從長遠看也極大的降低了工作量。
代碼最佳化的目標是:
減小代碼的體積
提高代碼啟動並執行效率
本文的內容有些來自網路,有些來自平時工作和學習,當然這不重要,重要的是這些代碼最佳化的細節是否真真正正地有用。那本文會保持長期更新,只要有遇到值得分享的代碼最佳化細節,就會不定時地更新此文。
1. 盡量指定類、方法的final修飾符
帶有final修飾符的類是不可派生的。在Java核心API中,有許多應用final的例子,例如java.lang.String,整個類都是final的。為類指定final修飾符可以讓類不可以被繼承,為方法指定final修飾符可以讓方法不可以被重寫。
如果指定了一個類為final,則該類所有的方法都是final的。Java編譯器會尋找機會內聯所有的final方法,內聯對於提升Java運行效率作用重大,具體參見Java運行期最佳化。此舉能夠使效能平均提高50%。
2. 盡量重用對象
特別是String對象的使用,出現字串串連時應該使用StringBuilder/StringBuffer代替。由於Java虛擬機器不僅要花時間產生對象,以後可能還需要花時間對這些對象進行記憶體回收和處理,因此,產生過多的對象將會給程式的效能帶來很大的影響。
3. 儘可能使用局部變數
調用方法時傳遞的參數以及在調用中建立的臨時變數都儲存在棧中,速度較快,其他變數,如靜態變數、執行個體變數等,都在堆中建立,速度較慢。
另外,棧中建立的變數,隨著方法的運行結束,這些內容就沒了,不需要額外的記憶體回收。
4. 及時關閉流
Java編程過程中,進行資料庫連接、I/O流操作時務必小心,在使用完畢後,及時關閉以釋放資源。因為對這些大對象的操作會造成系統大的開銷,稍有不慎,將會導致嚴重的後果。
5. 盡量減少對變數的重複計算
明確一個概念,對方法的調用,即使方法中只有一句語句,也是有消耗的,包括建立棧幀、調用方法時保護現場、調用方法完畢時恢複現場等。所以例如下面的操作:
for (int i = 0; i < list.size(); i++)
{…}
建議替換為:
for (int i = 0, length = list.size(); i < length; i++)
{…}
這樣,在list.size()很大的時候,就減少了很多的消耗。
6. 盡量採用懶載入的策略,即在需要的時候才建立
例如:
String str = “aaa”;
if (i == 1) {
list.add(str);