为啥字符串连接比 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_getCharsInteger.getChars 的实现还有其他细微差别,但我想它们对性能的影响并不大。


顺便说一句,如果您采用更大的数字(例如 1234567890),性能差异将可以忽略不计,因为 Integer.getChars 中的 extra loop 一次转换两位数。

【讨论】:

以上是关于为啥字符串连接比 String.valueOf 将 Integer 转换为 String 更快?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 String.valueOf(null) 会抛出 NullPointerException?

如何将long类型转化为string

字符串转化使用String.valueOf(value) 代替 “ “ + value

java String.valueOf(null)为啥会报空指针

String.valueOf()方法的使用

String.valueOf()方法的使用