Java中的Integer.toString(int i)和String.valueOf(int i)有什么区别?

196
我想知道为什么方法String.valueOf(int i)存在?我正在使用这个方法将int转换成String,但刚刚发现了Integer.toString(int i)方法。
在查看这些方法的实现后,我发现第一个方法调用了第二个方法。因此,所有对String.valueOf(int i)的调用都比直接调用Integer.toString(int i)多进行了一次调用。

3
仅供参考:https://dev59.com/FXA75IYBdhLWcg3wW3y8 - Bobby
主要是为了让编译器在将基本类型与字符串连接时,只需生成String.valueOf()调用,而无需了解所有的toString()方法。 - user207421
12个回答

183

在String类型中,我们有几个valueOf方法。

static String   valueOf(boolean b) 
static String   valueOf(char c) 
static String   valueOf(char[] data) 
static String   valueOf(char[] data, int offset, int count) 
static String   valueOf(double d) 
static String   valueOf(float f) 
static String   valueOf(int i) 
static String   valueOf(long l) 
static String   valueOf(Object obj) 

我们可以看到,这些方法能够解决各种类型的数字。

就像您展示的特定方法的每个实现一样:对于整数,我们有

Integer.toString(int i)

用于双精度类型

Double.toString(double d)

等等还有其他的。

在我看来,这不是什么历史遗留问题,而是对于开发者来说更有用的方法是从String类中使用valueOf方法,而不是从正确类型中使用,因为这样可以减少我们在想要改变操作类型时需要做出的更改。

示例1:

public String doStuff(int num) {

  // Do something with num...

  return String.valueOf(num);

 }

示例2:

public String doStuff(int num) {
  
 // Do something with num...
 
 return Integer.toString(num);

 }

正如我们在示例2中看到的那样,与示例1相比,我们需要进行两个更改。

我的结论是,使用String类中的valueOf方法更加灵活,这也是为什么它可用的原因。


19
别忘了Integer.toString(int i, int radix),它可以将数字转换为除十进制以外的其他进制字符串。 - Stephen P
@Vash,您能否解释一下使用空字符串将int转换为String与使用String.valueOf的区别?例如)"" + int i = "i"?哪个更好? - Kanagavelu Sugumar
1
要将int格式化为字符串,您不应该使用"" + i。虽然没有太大的开销,但通常因为这不够优雅。您可以使用String.format(“%d”,i);而不是使用String.valueOf(int)。要了解更多信息,请访问此网站http://docs.oracle.com/javase/6/docs/api/java/util/Formatter.html。 - Damian Leszczyński - Vash
我希望自动装箱更加智能一些,可以在编译时添加转换或者其他处理。 - Rob Grant
1
@RobertGrant 这里并不涉及自动装箱。但是为了回答你的疑虑,这种方式很巧妙,你可以这样做 int i = new Integer("1"); 反之亦然。 - Damian Leszczyński - Vash
显示剩余4条评论

59

一个巨大的区别在于,如果你在一个空对象中调用 toString() 方法,你会得到一个 NullPointerException 异常,而使用 String.valueOf() 方法时,你可能不需要检查是否为null。


51
这个问题涉及到Integer.toString(int i),这是一个静态方法。其中不可能出现null对象。 - Petr Janeček
18
Integer i = null; i.toString(); // 空指针异常! String.valueOf(i); // 没有异常翻译:Integer i = null;表示将一个空对象赋值给整型包装类Integer类型的变量ii.toString(); // 空指针异常!表示试图将这个空对象转换成字符串,因为它是空对象,所以会出现空指针异常。 String.valueOf(i); // 没有异常则是将i转化为字符串,由于String.valueOf()方法可以处理null值,所以不会出现异常。 - Manish Singh
13
@Manis KumarпјҡдҪ зҡ„зӨәдҫӢдёҚдјҡи§ҰеҸ‘String.valueOf(int i)ж–№жі•пјҢиҖҢжҳҜи§ҰеҸ‘дәҶString.valueOf(Object obj)ж–№жі•гҖӮж— и®әеҰӮдҪ•пјҢй—®йўҳж¶үеҸҠеҺҹе§Ӣзҡ„intеҖјпјҢеңЁиҝҷз§Қжғ…еҶөдёӢдёҚеӯҳеңЁnullзҡ„еҸҜиғҪжҖ§гҖӮ - hleinone
1
@manish_s 从示例中很清楚,没有人谈论对象类型Integer。我们只谈论原始数据类型。 - Daniel Ochoa
4
楼上的 @manish_s 说的是,原帖并没有提到 Integer.toString(),而是 Integer.toString(int i)。这是一个静态方法(http://docs.oracle.com/javase/7/docs/api/java/lang/Integer.html#toString(int))。 - LarsH

50

这只是同一件事情的两种不同做法。可能是由于历史原因造成的(不能确定哪一个先出现)。


25
是的,但如果某物正在做相同的事情,并不意味着它们是同一件事。 - Damian Leszczyński - Vash
5
String.valueOf(int) 直接调用了 Integer.toString(i),因此最好直接调用 Integer.toString(int)。请注意,该翻译保留了原文的含义和语气,并尽可能简洁易懂地传达了信息。 - djchapm

13

String类提供了所有基本类型和Object类型的valueOf方法,因此我认为它们是便利方法,可以通过一个类访问所有这些方法。

NB分析结果

intToString的平均值=5368ms,stringValueOf的平均值=5689ms(对于100,000,000个操作)

public class StringIntTest {


    public static long intToString () {
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 100000000; i++) {
            String j = Integer.toString(i);
        }
        long finishTime = System.currentTimeMillis();

        return finishTime - startTime;
    }

    public static long stringValueOf () {

        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 100000000; i++) {
            String j = String.valueOf(i);
        }
        long finishTime = System.currentTimeMillis();

        return finishTime - startTime;
    }

    public static void main(String[] args) {
        long intToStringElapsed = 0;
        long stringValueOfElapsed = 0;
        for (int i = 0; i < 10; i++) {
            intToStringElapsed += intToString();
            stringValueOfElapsed+= stringValueOf();
        }
        System.out.println("Average intToString = "+ (intToStringElapsed /10));
        System.out.println("Average stringValueOf = " +(stringValueOfElapsed / 10));
    }
}

7
如果你的剖析(profiling)没有“热身期”,那么结果可能会因JIT调整而产生偏差。话虽如此,在10^8次操作中出现300ms的差异是非常微不足道的。 - Cameron Skinner
1
@Kingo,我认为你的测试用例不正确。因为你将值分配给了String j,但从未使用过。底层编译器可能已经进行了优化。最好将j对象传递到不同的方法中并执行一些虚拟操作。 - Rakesh
1
你真的不应该这样编写自己的微基准测试。如果你使用JMH,它会处理预热、时间测量、多个独立尝试(forks Java!)并使代码更小,看起来像这样(包括不同方法和值的结果 - 运行时间7分钟):https://gist.github.com/ecki/399136f4fd59c1d110c1 (剧透:""+n 赢了)。 - eckes
6
谢谢,伙计,但是我的回答是5年前的!JMH只在2013年发布 :P - Kingo

11

来自Java源代码:

/**
 * Returns the string representation of the {@code int} argument.
 * <p>
 * The representation is exactly the one returned by the
 * {@code Integer.toString} method of one argument.
 *
 * @param   i   an {@code int}.
 * @return  a string representation of the {@code int} argument.
 * @see     java.lang.Integer#toString(int, int)
 */
public static String valueOf(int i) {
    return Integer.toString(i);
}

所以它们会得到完全相同的结果,实际上一个调用了另一个。String.valueOf更加灵活,如果将来可能更改类型。


9
如果你查看String类的源代码,实际上在调用valueOf()时会调用Integer.toString()
尽管如此,如果方法调用在编译时未进行优化(它们可能会进行优化),Integer.toString()可能会略微更快些。

1
是的,""+n 更快。请参见 https://gist.github.com/ecki/399136f4fd59c1d110c1 - eckes

3
您看到的 String.valueOf() 的实现是满足 API 中指定的契约的最简单的方式: "表示形式与一个参数的 Integer.toString() 方法返回的形式完全相同。"

3
为了回答OP的问题,这只是一个帮助器包装,用于调用其他函数,这只是样式选择的问题。我认为这里有很多错误信息,Java开发人员最好做的事情就是查看每个方法的实现,在任何IDE中都只需要单击一两下。你会清楚地看到String.valueOf(int)只是为您调用Integer.toString(int)。
因此,它们之间绝对没有区别,它们都创建一个char缓冲区,在数字中遍历,然后将其复制到新的字符串中并返回它(因此每个都创建一个字符串对象)。唯一的区别是多了一个调用,但编译器会将其消除为单个调用。
因此,无论你调用哪个方法都没有关系,除了可能代码一致性外。至于关于null的评论,它接受原始类型,因此它不能为null!如果您不初始化传递的int,则会在编译时出现错误。因此,在处理null方面没有差异,因为在这种情况下不存在null。

请你把文本分成几个块,这样阅读起来会容易一些。 - Magnilex
这篇帖子中有很多误解。你的帖子对我来说是最好的答案!谢谢。 - aksappy

2

你不必担心这个额外的调用会导致效率问题。如果有成本,它将是最小的,在大局中应该是可以忽略不计的。

也许两者都存在的原因是为了提供可读性。在将许多类型转换为 String 的上下文中,使用各种调用 String.valueOf(SomeType) 可能比使用各种 SomeType.toString 调用更容易阅读。


1
实际上,这样的单行调用很快就会被内联。 - Tassos Bassoukos
即使在循环中调用1,000,000次String.valueof() ?? - Manuel Selva
@Manuel:你有对其进行性能分析吗?你确定这就是你的性能问题所在吗?你确定你没有过早优化吗? @Tassos:是的,那也很可能,但无论如何,除非分析表明这个特定调用存在问题,否则不必担心它。 - polygenelubricants
实际上,Manuel,我期望循环执行1000000次比只执行一两次更容易被内联。即便如此,无论循环多少次,它都只占用很小一部分时间。 - corsiKa
不过我确定我的应用程序没有瓶颈。我只是问这个问题,因为我在这里看不到任何可读性问题,因此即使收益为0,我认为我必须使用更优化的代码。你不同意吗? - Manuel Selva

1
我的观点是valueof()总是调用tostring()来表示原始类型的值,并且对于原始类型的表示,valueof是通用的。Java默认不支持数据类型,但它定义了与对象和类一起工作的方式,将所有内容都放在类中并创建对象。在这里,Integer.toString(int i)创建了一个仅限于整数的转换限制。

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