關於java字符串經常使用一些api 效率比拼小結(java對大型的字符串api處理效率比拼)

好比說咱們要處理幾十萬個的字符串的處理,可能好比字符串的正則替換,好比replace、replaceAll,字符串的拼接或添加使用 +,StringBuilder的append,字符串的分割使用split。然而每每若是咱們的數據量很小的時候,其實看不出來有任何的問題。下面咱們來看看他們的底層作了些什麼java

一、咱們先來看replace和replaceAll,根據api,replace是不支持正則表達式,replaceAll是支持正則表達式的。正則表達式

下面看下replaceAll底層實現,因爲篇幅關係,只貼部分的主要代碼api

public String replaceAll(String regex, String replacement) {
    return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}
public String replaceAll(String replacement) {
    reset();
    boolean result = find(); //這兒主要是遍歷看是否有匹配的第一個字符,若是沒有直接返回,若是整個字符串沒有字符就直接return了
    if (result) {
        StringBuffer sb = new StringBuffer();
        do {
            appendReplacement(sb, replacement);//有的話對第一次find的字符進行添加
            result = find();//繼續尋找,一直尋找到末尾的時候沒有了就直接跳出do循環
        } while (result);
        appendTail(sb);
        return sb.toString();
    }
    return text.toString();
}

因此replaceAll是遍歷兩次數組

String.replace  主要由兩個函數,它不支持正則替換,app

replace(CharSequence target, CharSequence replacement)//字符替換,好比「abc」一串的字符替換一個「a」,從匹配是不是「abc」來講,和下面字符替換確定計算更多一些的,具體的不貼代碼了,比較冗長。
replace(char oldChar, char newChar)//字符串替換,通常來講替換單個字符,使用它,效率高,一樣的替換replace("a","b") 和替換replace('a','b')過程是不同的,後面的效率高。
public String replace(char oldChar, char newChar) {
    if (oldChar != newChar) {//若是相等就直接返回了喔
        int len = value.length;
        int i = -1;
        char[] val = value; /* avoid getfield opcode */

        while (++i < len) {
            if (val[i] == oldChar) {// i值 定位到第一個字符,利於下面縮減替換的區間
                break;
            }
        }
        if (i < len) {
            char buf[] = new char[len];//建立char數組
            for (int j = 0; j < i; j++) {
                buf[j] = val[j];//先裝起來前面沒有須要替換的匹配過的數組
            }
            while (i < len) {
                char c = val[i];
                buf[i] = (c == oldChar) ? newChar : c;//後面的匹配替換
                i++;
            }
            return new String(buf, true);//返回結果
        }
    }
    return this;
}

可見replace的替換char字符效率上是高replace替換字符串和replaceAll的,在效率上來講,若是處理字符串少,應該沒什麼問題的,可是若是處理超過幾十萬字符的計算那就很是耗時了,,或者替換的字符很少,能夠用replace替換char的api,或者本身實現,由於遍歷少,效率高。函數

測試效率可參考 別人寫的文章https://blog.csdn.net/zhanglianyu00/article/details/78296277測試

二、而後咱們字符串的拼接,咱們可使用加號 + 或者使用StringBuilder或StringBuffer的append,到底哪一個好。大數據

字符串的拼接 好比 String s = s1 + s2;這兒其實作了好幾步,首先看s1是否在字符靜態池中,java中有這個概念,有的話,就直接拿出來用,s2若是沒有的話,就建立,而後第二步進行字符串的拼接,這兒按照我的理解是,它底層實現,或許是先開闢一個內存,而後對s1和s2進行復制到s指向地址的內存中,這樣其實就是 一、靜態字符池中查找、建立 二、開闢內存複製 ,過程天然比stringBuilder複雜多了。ui

StringBuilder 底部有個重要的代碼this

 

/**
 * Copies an array from the specified source array, beginning at the
 * specified position, to the specified position of the destination array.

//註釋大概意思是 複製從指定源數組開始指定srcBegin開始複製指定須要複製的數組。翻譯有點蹩腳~

System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);//主要是數組的複製,這個api底層是jni調用底層的實現

//依據我的最近學c的猜測,應該避免不了都是動態擴展內存,指針去擴充字符內容。遍歷次數我以爲認爲是1次能夠解決。

而後咱們看比較他們字符拼接效率:

public static void a() {
        long starTime = new Date().getTime();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 500000; i++) {

            sb.append(String.valueOf(i));
        }
        long endTime = new Date().getTime();
        System.out.println("「append」號底層替換花費時間:" + (endTime - starTime));
    }

    public static void b() {
        long starTime = new Date().getTime();
        String string = new String();
        for (int i = 0; i < 500000; i++) {
            string += i;
        }
        long endTime = new Date().getTime();
        System.out.println("「+=」號花費時間:" + (endTime - starTime));

    }

「append」號底層替換花費時間:47
「+=」號花費時間:3598

在我機器上運行是這樣 StringBuilder拼接耗時47毫秒和 加號是3000多毫秒。因此咱們儘可能使用stringbuilder。

三、最後咱們看下split,因爲String.split方法會調用到CopyOfRange方法,在大數據量的狀況下,效率很低,因此改用StringTokenizer類實現String.split的功能

StringTokenizer stringTokenizer = new StringTokenizer(dataStr,",");
while(stringTokenizer.hasMoreTokens()){
    String eme = stringTokenizer.nextToken();

}

大概小結這樣。

相關文章
相關標籤/搜索