生活不僅眼前的苟且。還有讀不懂的詩和到不了的遠方。 --閆妮正則表達式
建議52:推薦使用String直接賦值算法
建議53:注意方法中傳遞的參數要求編程
建議54:正確使用String、StringBuffer、StringBuilder數組
建議55:注意字符串的位置安全
建議56:自由選擇字符串的拼接方法app
建議57:推薦在複雜字符串操做中使用正則表達式性能
建議58:強烈建議使用UTF編碼測試
建議59:對字符串持有一種寬容的心態ui
建議52:推薦使用String直接賦值this
建議53:注意方法中傳遞的參數要求
建議54:正確使用String、StringBuffer、StringBuilder
一、Java String類
字符串普遍應用在Java編程中,在Java中字符串屬於對象,Java提供了String類來建立和操做字符串。
須要注意的是String的值是不可變的,這就致使每次對String的操做都會生成新的String對象,這樣不只效率低下,並且浪費有限的內存空間。
咱們能夠看到,初始String值爲「hello」,而後在這個字符串後面加上新的字符串「world」,這個過程是須要從新在棧堆內存中開闢內存空間的,最終獲得了「hello world」字符串也相應的須要開闢內存空間,這樣短短的兩個字符串,卻須要開闢三次內存空間,不得不說這是對內存空間的極大浪費。爲了應對常常性的字符串相關的操做,Java引入了兩個新的類——StringBuffer類和StringBuild類來對此種變化字符串進行處理。
二、StringBuffer 和 StringBuilder 類
三者區別:
string:不可變字符序列
StringBuffer:可變字符序列、線程安全、效率低
StringBuilder:可變字符序列、線程不安全、效率高
注:
String的使用陷阱:
String ss = "a";
ss +="b";
若是屢次執行這些改變字符串內容的操做,會致使大量副本字符串對象存在內存中,下降效率。若是這樣的操做放在循環中,會極大影響程序的性能。
三、性能測試
String的拼接與StringBuilder的使用對比,簡單的12個字符串的循環解析拼接,相差了28毫秒,沒有對比就沒有傷害,之後用StringBuilder吧,暫時還不知道這個東西會有什麼弊端,持續觀察吧
建議55:注意字符串的位置
public class Client55 { public static void main(String[] args) { String str1 = 1 + 2 + "apples"; String str2 = "apples" + 1 + 2; System.out.println(str1); System.out.println(str2); } }
答案是不一致,str1的值是"3apples" ,str2的值是「apples12」。
建議56:自由選擇字符串的拼接方法
package OSChina.Client; public class Client1 { public static void main(String[] args) { // 加號拼接 String str = ""; long start1 = System.currentTimeMillis(); for (int i = 0; i < 100000; i++) { str += "江疏影"; } long end1 = System.currentTimeMillis(); System.out.println("加號拼接耗時:" + (end1 - start1) + "ms"); // concat拼接 str = ""; long start2 = System.currentTimeMillis(); for (int i = 0; i < 100000; i++) { str = str.concat("江疏影"); } long end2 = System.currentTimeMillis(); System.out.println("concat拼接耗時:" + (end2 - start2) + "ms"); // StringBuilder拼接 str = ""; StringBuilder buffer = new StringBuilder(""); long start3 = System.currentTimeMillis(); for (int i = 0; i < 10000000; i++) { buffer.append("江疏影"); } long end3 = System.currentTimeMillis(); System.out.println("StringBuilder拼接耗時:" + (end3 - start3) + "ms"); // StringBuffer拼接 str = ""; StringBuffer sb = new StringBuffer(""); long start4 = System.currentTimeMillis(); for (int i = 0; i < 10000000; i++) { sb.append("江疏影"); } long end4 = System.currentTimeMillis(); System.out.println("StringBuffer拼接耗時:" + (end4 - start4) + "ms"); } }
從上面的執行結果來看,在字符串拼接方式中,StringBuilder的append方法最快,StringBuffer的append方法次之(由於StringBuffer的append方法是線程安全的,同步方法天然慢一點),其次是concat方法,加號最慢,這是爲什麼呢?
速度:StringBuilder>StringBuffer>concat>String+
原理:
一、「+」方法拼接字符串:
str= new StringBuilder(str).append("c").toString();
它與純粹使用StringBuilder的append方法是不一樣的:一是每次循環都會建立一個StringBuilder對象,二是每次執行完畢都要調用toString方法將其轉換爲字符串——它的執行時間就耗費在這裏了!
二、concat方法拼接字符串:咱們從源碼上看一下concat方法的實現,代碼以下:
public String concat(String str) { int otherLen = str.length(); //若是追加字符長度爲0,則返回字符串自己 if (otherLen == 0) { return this; } int len = value.length; char buf[] = Arrays.copyOf(value, len + otherLen); str.getChars(buf, len); //產生一個新的字符串 return new String(buf, true); }
其總體看上去就是一個數組拷貝,雖然在內存中處理都是原子性操做,速度很是快,不過,注意看最後的return語句,每次concat操做都會建立一個String對象,這就是concat速度慢下來的真正緣由,它建立了10萬個String對象呀。
三、append方法拼接字符串:StringBuilder的append方法直接由父類AbstractStringBuilder實現,其代碼以下:
public AbstractStringBuilder append(String str) { //若是是null值,則把null做爲字符串處理 if (str == null) str = "null"; int len = str.length(); ensureCapacityInternal(count + len); //字符串複製到目標數組 str.getChars(0, len, value, count); count += len; return this; }
整個append方法都在作字符數組處理,加長,而後拷貝數組,這些都是基本的數據處理,沒有建立任何對象,因此速度也就最快。
四、StringBuffer的處理和此相似,只是方法是同步的而已。
建議57:推薦在複雜字符串操做中使用正則表達式
建議58:強烈建議使用UTF編碼
注:一個系統使用統一的編碼。
建議59:對字符串持有一種寬容的心態
中文的排序問題很混亂,Java使用UNICODE編碼,而中文UNICODE字符集來源於GB2312,GB2312是一個包含了7000多個字符的字符集,它是按照拼音排序,而且是連續的,以後的GBK、GB18030都是在其基礎上擴充而來的,因此要讓它們完整的排序也就難上加難了。
若是排序對象是常用的漢字,使用Collator類排序徹底能夠知足咱們的要求,畢竟GB2312已經包含了大部分的漢字,若是須要嚴格排序,則要使用一些開源項目來本身實現了。
注意:若是排序不是一個關鍵算法,使用Collator類便可。