为啥字符串连接比 String.valueOf 将 Integer 转换为 String 更快?
Posted
技术标签:
【中文标题】为啥字符串连接比 String.valueOf 将 Integer 转换为 String 更快?【英文标题】:Why is String concatenation faster than String.valueOf for converting an Integer to a String?为什么字符串连接比 String.valueOf 将 Integer 转换为 String 更快? 【发布时间】:2017-06-30 20:12:58 【问题描述】:我有一个基准:
@BenchmarkMode(Mode.Throughput)
@Fork(1)
@State(Scope.Thread)
@Warmup(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS, batchSize = 1000)
@Measurement(iterations = 40, time = 1, timeUnit = TimeUnit.SECONDS, batchSize = 1000)
public class StringConcatTest
private int aInt;
@Setup
public void prepare()
aInt = 100;
@Benchmark
public String emptyStringInt()
return "" + aInt;
@Benchmark
public String valueOfInt()
return String.valueOf(aInt);
这是结果:
Benchmark Mode Cnt Score Error Units
StringConcatTest.emptyStringInt thrpt 40 66045.741 ± 1306.280 ops/s
StringConcatTest.valueOfInt thrpt 40 43947.708 ± 1140.078 ops/s
它表明将空字符串与整数连接比调用 String.value(100) 快 30%。 我知道 "" + 100 转换为
new StringBuilder().append(100).toString()
并应用了-XX:+OptimizeStringConcat
优化,使其速度更快。我不明白为什么valueOf
本身比串联慢。
有人可以解释到底发生了什么以及为什么 "" + 100 更快。 OptimizeStringConcat
有什么魔力?
【问题讨论】:
"" + 100
对于编译器来说可能更清楚地识别为常量......
其中之一是方法调用。另一个,编译器可以随心所欲地编译。
@LouisWasserman 它未编译为常量。编译为StringBuider()
构造。
JIT 通常不会在较小的运行中发挥作用。你给了基准什么样的热身?
我同意这里的情况似乎并非如此。由于我在上面链接到的讨论,一般情况下不一定如此,在未来的编译器版本中也不一定如此。
【参考方案1】:
正如您所提到的,HotSpot JVM 具有 -XX:+OptimizeStringConcat
优化,可识别 StringBuilder 模式并将其替换为高度调整的手写 IR 图,而 String.valueOf()
依赖于一般编译器优化。
通过分析生成的汇编代码,我发现了以下主要区别:
优化的 concat 不会为结果字符串创建char[]
数组,而 Integer.toString
创建的数组在分配后会像任何其他常规对象一样被清除。
优化的 concat 通过简单的 addition of '0' constant 将数字转换为字符,而 Integer.getChars
使用 table lookup 以及相关的数组边界检查等。
PhaseStringOpts::int_getChars
与 Integer.getChars
的实现还有其他细微差别,但我想它们对性能的影响并不大。
顺便说一句,如果您采用更大的数字(例如 1234567890),性能差异将可以忽略不计,因为 Integer.getChars
中的 extra loop 一次转换两位数。
【讨论】:
以上是关于为啥字符串连接比 String.valueOf 将 Integer 转换为 String 更快?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 String.valueOf(null) 会抛出 NullPointerException?
字符串转化使用String.valueOf(value) 代替 “ “ + value