在Java中连接空字符串

yav*_*voh 157 java string concatenation string-concatenation

为什么以下工作?我希望有人会NullPointerException被扔掉.

String s = null;
s = s + "hello";
System.out.println(s); // prints "nullhello"
Run Code Online (Sandbox Code Playgroud)

Mar*_*ers 180

为什么一定有用?

JLS 5,第15.18.1.1节 JLS 8§15.18.1 "字符串连接运算符+" ,导致JLS 8,第5.1.11 "字符串转换",要求该操作无故障成功:

......现在只需要考虑参考值.如果引用为null,则将其转换为字符串"null"(四个ASCII字符n,u,l,l).否则,执行转换就好像通过调用没有参数的引用对象的toString方法一样; 但是如果调用toString方法的结果为null,则使用字符串"null".

它是如何工作的?

我们来看看字节码吧!编译器接受你的代码:

String s = null;
s = s + "hello";
System.out.println(s); // prints "nullhello"
Run Code Online (Sandbox Code Playgroud)

并将其编译为字节码,就像你写了这样:

String s = null;
s = new StringBuilder(String.valueOf(s)).append("hello").toString();
System.out.println(s); // prints "nullhello"
Run Code Online (Sandbox Code Playgroud)

(你可以自己使用javap -c)

StringBuilderall 的append方法处理null就好了.在这种情况下,因为null是第一个参数,String.valueOf()而是调用,因为StringBuilder没有采用任意引用类型的构造函数.

如果您已经完成了s = "hello" + s,那么等效的代码将是:

s = new StringBuilder("hello").append(s).toString();
Run Code Online (Sandbox Code Playgroud)

在这种情况下,append方法取null,然后将其委托给String.valueOf().

注意:字符串连接实际上是编译器决定执行哪些优化的罕见地方之一.因此,"完全等效"代码可能因编译器而异.JLS,第15.18.1.2节允许这种优化:

为了提高重复字符串连接的性能,Java编译器可以使用StringBuffer类或类似技术来减少通过计算表达式创建的中间String对象的数量.

我用来确定上面"等效代码"的编译器是Eclipse的编译器,ecj.

  • `StringBuilder`在技术上不使用`String.valueOf`如果除了`append(Object)`之外的任何`append`方法(例如`append(String)`或`append(CharSequence)`)被调用,尽管`null`无论如何都变为"null". (3认同)

Jon*_*ust 25

请参阅Java语言规范的第5.415.18节:

当其中一个参数是String时,字符串转换仅适用于binary +运算符的操作数.在这个单一的特殊情况下,+的另一个参数被转换为一个String,而一个新的String是两个字符串的串联,是+的结果.字符串转换在字符串连接+运算符的描述中详细指定.

如果只有一个操作数表达式是String类型,则在另一个操作数上执行字符串转换以在运行时生成字符串.结果是对String对象的引用(新创建,除非表达式是编译时常量表达式(第15.28节)),它是两个操作数字符串的串联.左侧操作数的字符位于新创建的字符串中右侧操作数的字符之前.如果String类型的操作数为null,则使用字符串"null"而不是该操作数.

  • 是! 最后回答一些不错的引号而不跳过'StringBuilder'(这是编译器可能执行或不执行的优化). (5认同)

Rol*_*lig 11

第二行转换为以下代码:

s = (new StringBuilder()).append((String)null).append("hello").toString();
Run Code Online (Sandbox Code Playgroud)

append方法可以处理null参数.


kri*_*ico 10

您没有使用"null",因此您没有得到异常.如果你想要NullPointer,那就行了

String s = null;
s = s.toString() + "hello";
Run Code Online (Sandbox Code Playgroud)

而且我认为你想要做的是:

String s = "";
s = s + "hello";
Run Code Online (Sandbox Code Playgroud)


wkl*_*wkl 7

这是Java API String.valueOf(Object)方法中指定的行为.进行连接时,valueOf用于获取String表示.如果是Object null,则会有一种特殊情况,在这种情况下使用字符串"null".

public static String valueOf(Object obj)

返回Object参数的字符串表示形式.

参数:obj - 一个Object.

返回:

如果参数为null,则字符串等于"null"; 否则,返回obj.toString()的值.