不能用 + 拼接字符串? 這次我要吊打面試官!


好久沒維護《吊打面試官》系列了,今天再來一篇,這次真的要吊打了,哈哈!(看往期吊打系列請在后台回復:吊打,我會陸續更新……)

我們做 Java 程序員以來,不管是工作當中,還是面試過程中,都知道:字符串拼接不能用 String,要用 StringBuilder 或者是 StringBuffer,以至於它們都被濫用了。

StringBuilder、StringBuffer 簡稱:SB,下文統一用 SB 代替。

SB它們都是可變的字符串,它們之間的區別也是 Java 初中級面試戰場上出現幾率十分高的一道題,上場率沒有 90% 也有 80% 吧。

這兩個的具體區別請看這篇文章

我們反過來想下,String真的是不可變的么?不一定,看下:Java 中的 String 真的是不可變的嗎?這篇。

當然,本文不是討論字符串可變與不可變的問題,而是討論:字符串拼接一定要用 SB 嗎?為什么不能用 + ?能不能用 + ?什么時候可以用 +

為什么不能用 + 號拼接字符串?我不服,接下來我要吊打面試官!

什么時候不能用 +

通過多個表達式完成一個字符串拼接操作。

private void test1() {
    String www = "www.";
    String str = www;
    str += "javastack.";
    str += "com";
}

字節碼如下:

// access flags 0xA
private static test2()V
L0
LINENUMBER 14 L0
LDC "www."
ASTORE 0
L1
LINENUMBER 15 L1
ALOAD 0
ASTORE 1
L2
LINENUMBER 16 L2
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
ALOAD 1
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
LDC "javastack."
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ASTORE 1
L3
LINENUMBER 17 L3
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
ALOAD 1
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
LDC "com"
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ASTORE 1
L4
LINENUMBER 18 L4
RETURN
L5
LOCALVARIABLE www Ljava/lang/String; L1 L5 0
LOCALVARIABLE str Ljava/lang/String; L2 L5 1
MAXSTACK = 2
MAXLOCALS = 2

不會查看字節碼的,看這里,就會了。

觀察下,NEW java/lang/StringBuilder 出現了兩次,是因為我們在代碼中拼接了兩次,也就是說每一次拼接操作都會創建一次 StringBuilder

如果我們是在一個循環中進行字符串拼接,那是不是一次拼接就要創建一個 StringBuilder

wtf……這哪能接受!頻繁創建對象是有性能開銷的,這也是為什么我們常說的字符串不能用 + 拼接,而要用那兩個 SB 拼接了。

什么時候可以用 +

直接將三個字面量的字符串拼接成一個字符串。

private static void test2() {
    String str = "www." + "javastack." + "com";
}

字節碼如下:

// access flags 0x2
private test2()V
L0
LINENUMBER 13 L0
LDC "www.javastack.com"
ASTORE 1
L1
LINENUMBER 14 L1
RETURN
L2
LOCALVARIABLE this Lcom/test/jdk/TestSB; L0 L2 0
LOCALVARIABLE str Ljava/lang/String; L1 L2 1
MAXSTACK = 1
MAXLOCALS = 2

從字節碼看出,沒有任何創建 StringBuilder 的指令,直接從常量池進行取出一個完整的字符串:www.javastack.com。很明顯,這是 Java 編譯器對代碼進行了優化。

所以,通過這個示例告訴你,在這種情況下是可以用 + 號進行字符串拼接的。

這個示例可以演變成我們實際工作當中的某個 SQL 語句拼接的案例,如:

String sql = "select name, sex, age, address"
        + "from t_user"
        + "where age > 18";

別說這樣不行,這樣是行的。

但你要是換成這樣就不行了:

String sql = "select name, sex, age, address";
sql += "from t_user";
sql += "where age > 18";

這樣又回到創建多個 StringBuilder 的時候了。

也就是說,在一個表達式中完成字符串拼接是可以用 + 號完成的,因為編譯器已經做了優化。

小結一下

你只需要記住這兩點:

1、在循環和多個表達式中不能 +,頻繁創建 SB 性能影響;

2、在單個表達式中可以用 +,編譯器直接做了優化;

老鐵們,都搞清楚了?

這個觀點有沒有被誤解很久?

下次面試,把這篇內容亮出來,吊打面試官,沒問題的。

有收獲的朋友一定要點個在看,這樣我寫原創更帶勁了,謝了,老鐵們。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM