第51條:當心字串連線的效能

weixin_34148340發表於2017-07-19

字串連線操作符(+)是把多個字串合併為一個字串的便利途徑。要想產生單獨一行的輸出,或者構造一個字串來表示一個較小的、大小固定的物件,使用連線操作符是非常合適的,但是它不適合運用在大規模的場景中。為連線n個字串而重複地使用字串連線操作符,需要n的平方級的時間。這是由於字串不可變而導致的不幸結果。當兩個字串被連線在一起時,他們的內容都要被拷貝。

例如:考慮下面的方法,它通過反覆連線每個專案行,構造出一個代表該對賬單的字串。程式碼如下:

    public String statement(){
        String result = "";
        for (int i = 0; i < numItems; i++ ){
            result += lineForItem(i);
            return result;
        }
    }

如果專案數量巨大,這個方法的執行時間就難以估算。為了獲得可以接受的效能,請使用StringBuffer替代String,來儲存建築中的對賬單。

    public String statement(){
        StringBuffer sb = new StringBuffer(numItems() * LINE_WIDTH);
        for (int i = 0; i < numItems(); i++ ){
            sb.append(lineForItem(i));
        }
        return sb.toString();
    }

上訴兩種做法的效能差別非常大。如果numItems返回100,並且lineForItem返回一個固定長度為80的字串,在作者的機器上,第二種做法比第一種做法要快85倍(書上的例子用的是StringBuilder)。因為第一種做法的開銷隨專案數量而呈平方級增加,所以,專案數越大,效能的差別會越顯著。

        long start = System.currentTimeMillis();
        String string = "aa";
        for (int i = 0; i < 100000; i++) {
            string += "a";
        }
        long end = System.currentTimeMillis();
        System.out.println(end - start);

        long start1 = System.currentTimeMillis();
        StringBuilder sb = new StringBuilder("aa");
        for (int i = 0; i < 100000; i++) {
            sb.append("a");
        }
        long end1 = System.currentTimeMillis();
        System.out.println(end1 - start1);

輸出結果:

5110
4

操作的數量越多 ,差距就越明顯

總結:不要使用字串連線操作符來合併多個字串,除非效能無關緊要。相反,應該使用StringBuffer的append方法。

相關文章