在Java中如何避免創(chuàng)建不必要的對象
簡介
在Java開發(fā)中,程序員要盡可能的避免創(chuàng)建相同的功能的對象,因為這樣既消耗內存,又影響程序運行速度。在這種情況下可以考慮重復利用對象。
接下來舉例幾種對象重復利用的場景,看看我們是不是有中招了,如果有趕緊趁著還沒被發(fā)現(xiàn)悄悄改掉,被發(fā)現(xiàn)了會被diss啦!
1、String和Boolean
如下兩種寫法看似沒有什么區(qū)別,但是如果深入jvm底層了解,我們可以利用jvm運行時常量池的特性,避免創(chuàng)建具有相同功能的String對象(尤其是在循環(huán)內部創(chuàng)建)可以帶來比較可觀的性能優(yōu)化以及節(jié)約內存。
錯誤寫法
// 每次都會創(chuàng)建一個新的String對象,且不會加入常量池
String name2 = new String("李子捌");
正確寫法
// 正確寫法 String name1 = "李子捌";
除此之外,剛寫Java代碼的程序員們,也要正確的選擇String、StringBuilder、StringBuffer類的使用。String為不可變對象,通常用于定義不變字符串;StringBuilder、StringBuffer用于可變字符串操作場景,如字符串拼接;其中StringBuffer是線程安全的,它通過Synchronized關鍵字來實現(xiàn)線程同步。
// StringBuffer中的append()方法
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
// StringBuilder中的append()方法
public StringBuilder append(String str) {
super.append(str);
return this;
}
Boolean是常用的類型,在開發(fā)中也應該使用Boolean.valueof()而不是new Boolean(),從Boolean的源碼可以看出,Boolean類定義了兩個final static的屬性,而Boolean.valueof()直接返回的是定義的這兩個屬性,而new Boolean()卻會創(chuàng)建新的對象。
public static final Boolean TRUE = new Boolean(true); public static final Boolean FALSE = new Boolean(false);
2、自動拆箱和裝箱
Java提供了基本數(shù)據(jù)類型的自動拆箱和裝箱功能,那是不是意味著我們可以在代碼中隨意的使用這兩個類型呢?其實理論上在代碼層面是沒得問題,不過在具體的性能方面還是有優(yōu)化的空間啦?。?!
我們來測試下性能
long start = System.currentTimeMillis();
Integer sum = 0;
for (int i = 0; i < 100000; i++) {
sum += i;
}
System.out.println(System.currentTimeMillis() - start);
使用Integer耗時3毫秒

long start = System.currentTimeMillis();
// 修改Integer 為 int
int sum = 0;
for (int i = 0; i < 100000; i++) {
sum += i;
}
System.out.println(System.currentTimeMillis() - start);
使用int耗時0毫秒

因此關于自動拆箱裝箱的使用,我們其實也可以做適當?shù)目紤],畢竟有時候代碼性能就是一點點擠出來的嘛!??!
3、正則表達式
正則表達式我們經(jīng)常用于字符串是否合法的校驗,我們先來看一段簡單的代碼(大家有沒有一眼看出問題呢?我想你肯定看出來了?。。。?/p>
public static void main(String[] args) {
String email = "1057301174@qq.com";
String regex = "^([a-z0-9A-Z]+[-|\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\.)+[a-zA-Z]{2,}$";
long start = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
email.matches(regex);
}
System.out.println(System.currentTimeMillis() - start);
}
執(zhí)行這段代碼的時間,一共耗時71毫秒,看似好像挺快的!

但是我們做個非常簡單的優(yōu)化,優(yōu)化后的代碼如下所示:
public static void main(String[] args) {
String email = "1057301174@qq.com";
String regex = "^([a-z0-9A-Z]+[-|\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\.)+[a-zA-Z]{2,}$";
Pattern pattern = Pattern.compile(regex);
long start = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
//email.matches(regex);
pattern.matcher(email);
}
System.out.println(System.currentTimeMillis() - start);
}
再次執(zhí)行代碼,一共耗時1毫秒,快了70倍呀?。。?/p>

這是因為String.matches()方法在循環(huán)中創(chuàng)建時,每次都需要執(zhí)行Pattern.compile(regex),而創(chuàng)建Patter實例的成本很高,因為需要將正則表達式編譯成一個有限狀態(tài)機( finite state machine)。這種我們經(jīng)常會因為Java api提供了比較方便的方法調用而忽略了性能考究,往往不容易被發(fā)現(xiàn)。這個時候就需要優(yōu)秀的你,去“咬文嚼字”啦!
總結
到此這篇關于在Java中如何避免創(chuàng)建不必要對象的文章就介紹到這了,更多相關Java避免創(chuàng)建不必要對象內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
JAVA對象JSON數(shù)據(jù)互相轉換的四種常見情況
這篇文章主要介紹了JAVA對象JSON數(shù)據(jù)互相轉換的四種常見情況,需要的朋友可以參考下2014-04-04
Java語言中finally是否一定會執(zhí)行你知道嗎
這篇文章主要為大家詳細介紹了Java finally是否一定會執(zhí)行,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-02-02
詳解Java實現(xiàn)JSONArray轉Map的三種實現(xiàn)方式
本文主要介紹了Java實現(xiàn)JSONArray轉Map的三種實現(xiàn)方式,本文只是自己常用的三種,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-03-03

