編寫高質量代碼:改善Java程序的151個建議(第4章:字符串___建議52~59)

生活不僅眼前的苟且。還有讀不懂的詩和到不了的遠方。 --閆妮正則表達式

建議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吧,暫時還不知道這個東西會有什麼弊端,持續觀察吧

ee4f3054569c9dee6d67fe1f0b1f096dda7.jpg

建議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類便可。

 

編寫高質量代碼:改善Java程序的151個建議@目錄

相關文章
相關標籤/搜索