将整数转换为字符串的最有效方法是什么?

69

假设我有:

int someValue = 42;

现在我想将那个 int 值转换为字符串。哪种方法更有效?

// One
String stringValue = Integer.toString(someValue);

// Two
String stringValue = String.valueOf(someValue);

// Three
String stringValue = someValue + "";

我只是好奇它们之间是否有任何真正的区别或者一个比另一个更好?


1
我正要问这个问题 xd - Evil Washing Machine
很高兴我已经为你找到了答案 :-) - Ascalonian
7个回答

81

我测试了数字10的10m次赋值操作

One:
real    0m5.610s
user    0m5.098s
sys     0m0.220s

Two:
real    0m6.216s
user    0m5.700s
sys     0m0.213s

Three:
real    0m12.986s
user    0m11.767s
sys     0m0.489s

看起来似乎胜出了。

编辑: 在 Mac OS X 10.5 下,JVM 的标准位置为 '/usr/bin/java'。

java version "1.5.0_16"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_16-b06-284)
Java HotSpot(TM) Client VM (build 1.5.0_16-133, mixed mode, sharing)

更多编辑:

按要求提供代码

public class One {
    public static void main(String[] args) {
        int someValue = 10;
        for (int i = 0; i < 10000000; i++) {
            String stringValue = Integer.toString(someValue);
        }
    }
}

类似于第2和第3个案例
使用以下方式运行

javac *.java; time java One; time java Two; time java Three

1
经过一段热身后,1和2应该会有相同的性能。大概。 - Tom Hawtin - tackline
2
我更喜欢使用String.valueOf(...),因为它是String类中的静态方法,返回一个字符串,而不是Integer类中返回整数的静态方法。这似乎是更合适的做法。 - Ravi Wallau
1
但是 String.valueOf(s) 的源代码是 "return Integer.toString(s)"。 - Gilian
如果编译器仍然不知道如何优化 ""+int,我会感到惊讶... 如果不知道,最终它们应该会认识到并将其转换为简单的字符串。在那时,它将是最快的,因为您节省了一些按键。 - Patrick Parker
2
通过预热,在最近的JDK上,我得到非常非常不同的结果:基本上是一场平局。 - tucuxi

37
尽管根据cobbal的测量值,#1似乎是最快的,但我强烈建议使用String.valueOf()。我的理由是这个调用不明确包含参数的类型,因此,如果以后你决定将其从int更改为double,则无需修改此调用。与#2相比,#1的速度增益仅仅是微不足道的,并且我们都知道,“过早地优化是万恶之源”。第三种解决方案是不可行的,因为它隐式创建了一个StringBuilder并将组件(在本例中是数字和空字符串)附加到其中,最后将其转换为字符串。

基准测试结果与 ""+i 很慢的说法不符。它似乎被优化为与其他替代方案一样快。 - tucuxi

8

看一下JRE的源代码,你可能会看到差异。或者没有任何差异。 事实上,String.valueOf(int foo)的实现如下:

public static String valueOf(int i) {
    return Integer.toString(i, 10);
}

还有 Integer.toString(int foo, int radix) 方法

public static String toString(int i, int radix) {
   ...
   if (radix == 10) {
   return toString(i);
   }
   ...
}

这意味着如果您使用十进制,最好直接调用Integer.toString(int foo)。对于其他情况,请使用Integer.toString(int foo, int radix)。

连接字符串的解决方案首先将int值转换为String,然后与空字符串连接。这显然是最昂贵的情况。


但如果这条路径经常被使用,我相信JVM将能够进行乐观的内联优化,使性能达到等效。 - Michael Myers
区别在于另一个函数调用! - Bojan Kseneman

8

前两个示例实际上是相同的,因为String.valueOf(int)使用了Integer.toString(int)方法。第三个示例很丑陋,而且可能不够高效,因为在Java中连接操作速度较慢。


5

(与David Hanak相反。)

尽管根据cobbal的测量结果,#1似乎是最快的,但我强烈建议使用Integer.toString()。我的理由是,这个调用明确地包含了参数的类型,因此如果以后你决定将它从int改为double,那么就清楚地知道这个调用已经改变了。如果是二进制格式,你也会这样做,对吧?与#2相比,#1的速度增益仅仅是微不足道的,并且众所周知,“过早的优化是万恶之源”。


作为一名高级编程语言的程序员,我现在并不关心我的参数类型;我只想要它的字符串表示。String.valueOf()清晰地表达了这一点。在我看来。 - David Hanak
说实话,String.valueOf并不一定会为所有变量返回与Integer.toString(int)相同的结果或执行相同的操作。正是这些意想不到的语义差异驱使我变得更加明确。 - Tom Hawtin - tackline
如果意图或语义是“我想获取除整数以外的其他类型对象的字符串形式”,则String.valueOf更能表达这一点。如果意图或语义是“我必须取一个整数,并获得它的字符串形式”,则Integer.toString更能表达这一点。 - mtraceur

3

"" + int的速度比David Hanak所示要慢。

String.valueOf()调用Integer.toString()。因此,使用Integer.toString()更好。

因此,Integer.toString()是最快的。


String.valueOf(int) 不是 String.valueOf(Object)! - Tom Hawtin - tackline
这是针对整数数据类型的...它直接调用Integer.toString()来处理int。 - Real Red.
问题是关于 int,而不是 Integer。 - Tom Hawtin - tackline
哦,拜托,我一开始只是忽略了这个。我的错。而且String.valueOf(int)调用的也是Integer.toString()。我试图表达的实质是,对String类的调用最终会转到Integer类,这已经被传达了。这个回答被点踩看起来很不好! - Real Red.

0

我的JDK 11微基准测试结果与目前被接受的答案非常不同,显示出最小的运行时间差异,并且完全没有内存使用/分配差异:

 t (ms)   method

 12,30    "" + j
 12,57    Integer.toString(j)
 12.58    String.valueOf(j)

我实际上编写了这个微基准测试来解决另一个问题; 一位评论者建议我也在这里发布。以下是用于复制的代码(也来自该帖子):

package org.example;

import com.google.caliper.BeforeExperiment;
import com.google.caliper.Benchmark;
import com.google.caliper.Param;
import com.google.caliper.runner.CaliperMain;

public class Main {

    @Param({"10", "100", "1000"})
    int size;

    private String[] output;

    @BeforeExperiment
    void setUp() {
        output = new String[size];
    }

    @Benchmark void quote(int reps) {
        for (int i = 0; i < reps; i++) {
            for (int j = 0; j < size; j++) {
                output[j] = "" + j;
            }
        }
    }

    @Benchmark void toString(int reps) {
        for (int i = 0; i < reps; i++) {
            for (int j = 0; j < size; j++) {
                output[j] = Integer.toString(j);
            }
        }
    }

    @Benchmark void valueOf(int reps) {
        for (int i = 0; i < reps; i++) {
            for (int j = 0; j < size; j++) {
                output[j] = String.valueOf(j);
            }
        }
    }

    /*
    must have com.google.caliper:caliper:1.0-beta-3 in pom.xml; run with:
    mvn clean compile exec:java -Dexec.mainClass="com.google.caliper.runner.CaliperMain" -Dexec.args="org.example.Main"
     */
    public static void main(String[] args) {
        CaliperMain.main(Main.class, args);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接