標籤:拆箱 相等 com -- 運算 length 資料量 多線程 str
編寫高品質代碼:改善Java程式的151個建議 --[52~64]推薦使用String直接量賦值
Java為了避免在一個系統中大量產生String對象(為什麼會大量產生,因為String字串是程式中最經常使用的類型),於是就設計了一個字串池(也叫作字串常量池,String pool或String Constant Pool或String Literal Pool),在字串池中容納的都是String字串對象,它的建立機制是這樣的:建立一個字串時,首先檢查池中是否有字面值相等的字串,如果有,則不再建立,直接返回池中該對象的引用,若沒有則建立之,然後放到池中,並返回建立對象的引用,這個池和我們平常說的池非常接近。對於此例子來說,就是建立第一個"詹姆斯"字串時,先檢查字串池中有沒有該對象,發現沒有,於是就建立了"詹姆斯"這個字串並放到池中,待建立str2字串時,由於池中已經有了該字串,於是就直接返回了該對象的引用,此時,str1和str2指向的是同一個地址,所以使用"=="來判斷那當然是相等的了。
public class Client58 { public static void main(String[] args) { //建議 String str1 = "詹姆斯"; //建議 String str2 = "詹姆斯"; //不建議,直接聲明一個String對象是不檢查字串池的,也不會把對象放到字串池中 String str3 = new String("詹姆斯"); String str4 = str3.intern(); // 兩個直接量是否相等 System.out.println(str1 == str2); // 直接量和對象是否相等 System.out.println(str1 == str3); // 經過intern處理後的對象與直接量是否相等, //intern會檢查當前對象在對象池中是否存在字面值相同的引用對象,如果有則返回池中的對象,如果沒有則放置到對象池中,並返回當前對象。 System.out.println(str1 == str4); }}
正確使用String、StringBuffer、StringBuilder
使用String類的情境:在字串不經常變化的情境中可以使用String類,例如常量的聲明、少量的變數運算等;
使用StringBuffer的情境:在頻繁進行字串的運算(如拼接、替換、刪除等),並且運行在多線程的環境中,則可以考慮使用StringBuffer,例如XML解析、HTTP參數解析和封裝等;
使用StringBuilder的情境:在頻繁進行字串的運算(如拼接、替換、刪除等),並且運行在單線程的環境中,則可以考慮使用StringBuilder,如SQL語句的拼接,JSON封裝等。
效能對比:
StringBuffer和StringBuilder基本相同,都是可變字元序列,不同點是:StringBuffer是安全執行緒的,StringBuilder是線程不安全的,翻翻兩者的原始碼,就會發現在StringBuffer的方法前都有關鍵字syschronized,這也是StringBuffer在效能上遠遠低於StringBuffer的原因。
在效能方面,由於String類的操作都是產生String的對象,而StringBuilder和StringBuffer只是一個字元數組的再擴容而已,所以String類的操作要遠慢於StringBuffer 和 StringBuilder。
強烈建議使用UTF編碼使用Collator類排序漢字
如果排序對象是經常使用的漢字,使用Collator類排序完全可以滿足我們的要求,畢竟GB2312已經包含了大部分的漢字,如果需要嚴格排序,則要使用一些開源項目來自己實現了,比如pinyin4j可以把漢字轉換為拼音,然後我們自己來實現排序演算法,不過此時你會發現要考慮的諸如演算法、同音字、多音字等眾多問題。
import java.text.Collator;import java.util.Arrays;import java.util.Comparator;import java.util.Locale;public class CollatorDemo { public static void main(String[] args) { String[] strs = { "張三(Z)", "李四(L)", "王五(W)" }; //定義一個中文排序器 Comparator c = Collator.getInstance(Locale.CHINA); Arrays.sort(strs,c); int i = 0; for (String str : strs) { System.out.println((++i) + "、" + str); } }}
結果:
1、李四(L)
2、王五(W)
3、張三(Z)
效能要求較高的情境中使用數組代替集合
對基本類型進行求和運算時,數組的效率是集合的10倍。
//對數組求和 public static int sum(int datas[]) { int sum = 0; for (int i = 0; i < datas.length; i++) { sum += datas[i]; } return sum; }
// 對列表求和計算 public static int sum(List<Integer> datas) { int sum = 0; for (int i = 0; i < datas.size(); i++) { sum += datas.get(i); } return sum; }
基本類型是在棧記憶體中操作的,而對象是堆記憶體中操作的,棧記憶體的特點是:速度快,容量小;堆記憶體的特點是:速度慢,容量大(從效能上講,基本類型的處理佔優勢)。其次,在進行求和運算時(或者其它遍曆計算)時要做拆箱動作,因此無謂的效能消耗也就產生了。
若有必要,使用變長數組
public static <T> T[] expandCapacity(T[] datas, int newLen) { // 不能是負值 newLen = newLen < 0 ? 0 : newLen; // 產生一個新數組,並拷貝原值 return Arrays.copyOf(datas, newLen); }
public static void main(String[] args) { //一個班級最多容納60個學生 Stu [] stuNums= new Stu[60]; //stuNums初始化...... //偶爾一個班級可以容納80人,數組加長 stuNums=expandCapacity(stuNums,80); /* 重新初始化超過限額的20人...... */ }
在明確的情境下,為集合指定初始容量
ArrayList():預設建構函式,提供初始容量為10的空列表。
ArrayList(int initialCapacity):構造一個具有指定初始容量的空列表。
ArrayList(Collection<? extends E> c):構造一個包含指定 collection 的元素的列表,這些元素是按照該 collection 的迭代器返回它們的順序排列的。
從這裡我們可以看出,如果不設定初始容量,系統會按照1.5倍的規則擴容,每次擴容都是一次數組的拷貝,如果資料量大,這樣的拷貝會非常消耗資源,而且效率非常低下。所以,我們如果知道一個ArrayList的可能長度,然後對ArrayList設定一個初始容量則可以顯著提高系統效能。
編寫高品質代碼:改善Java程式的151個建議 --[52~64]