将整数转换为字符串使用("" + <int value>)是不良实践吗?

18

在 Java 中将对象转换为字符串,通常使用

toString()

方法。

"" + <int value>

不好的做法?与 String.valueOf(...) 相比,它有什么缺点吗?

代码示例:

int i = 25;
return "" + i;

vs:


这是一个常见的缩写,通常代表“对比”。
int i = 25;
return String.valueOf(i);

更新:(来自评论)

那么,Integer.toString(int i)String.valueOf(...) 相比如何?


那么Integer.toString(int i)呢?(如果您将i更改为另一种类型,它将无法编译,这可能是好事或不好的事情) - Pascal Thivent
@Pascal Thivent:看看我的回答,似乎Integer.toString(int i)是最好的选择! - Kip
从性能角度来看,String.valueOf()可能仍然有可读性的优势,因为性能差异可以忽略不计。 - Kip
Integer.toString(i, 10) 相当于 String.valueOf(i)。 - Kevin
8个回答

35

我总是更倾向于使用String.valueOf版本:主要因为它展示了你想要做什么。目的不是字符串拼接-而是转换为字符串,“i的字符串值”。

第一种形式也可能效率低下 - 这取决于编译器是否发现你在做什么。如果没有,它可能会创建一个新的StringBuffer或StringBuilder并附加值,然后将其转换为字符串。

有趣的是,我有一篇关于这个问题的文章-写于多年前; 我网站上最早的Java文章之一,如果我没记错的话。


Jon Skeet,你有把这篇文章备份吗? - Zlatin Zlatev
@ZlatinZlatev:已编辑链接。虽然现在回答这个问题的时间比写文章和回答之间的时间更长了... - Jon Skeet

11

还有Integer.toString(int i),它可以让你选择将字符串作为十六进制值输出(通过传递第二个参数16)。

编辑 我刚刚查看了String类的源代码:

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

整数类:

public static String toString(int i, int radix) {
  if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
    radix = 10;

  /* Use the faster version */
  if (radix == 10) {
    return toString(i);
  }
  ...
如果你调用`String.valueOf(i)`,它会调用`Integer.toString(i, 10)`,然后再调用`Integer.toString(i)`。
因此,`Integer.toString(i)`比`String.valueOf(i)`稍微快一些,因为你省略了两个函数调用。(尽管第一个函数调用可以被编译器优化掉。)
当然,仍然可以通过可读性的论点来支持`String.valueOf()`,因为它允许你更改参数的类型(甚至处理null!),而且性能差异微不足道。

+1 检查源代码并反馈。虽然可能被认为是过早的优化,但仍是有用的信息。 - RHSeeger

10

一定要使用 String.valueOf(i)。

虽然我不确定编译器端的优化情况,但是如果你使用 "" + 的最坏情况是:

  1. "" 创建了一个新的空字符串。
  2. ""+ 创建一个 StringBuilder(Java 1.5-16)
  3. "" 被附加到 StringBuilder 上,然后

换句话说,如果你使用字符串拼接,会发生很多额外的开销。这就是为什么不建议在循环中使用字符串 "+" 运算符的原因。一般来说,尽可能使用 Boolean.valueOf、Integer.valueOf、String.valueOf 等方法。这样既可以节省内存,也可以减少开销。


""在每次迭代中不会创建一个新的空字符串。所有出现的""都将有一个单独的字符串。但是,是的,除非编译器捕获它,否则你最终会得到一个额外的StringBuilder。 - Jon Skeet
第一个空引号将被内部化,因此永远只会有一个(这是JLS的事情,不仅仅是可选优化)。 - Yishai
在循环中使用字符串的 + 操作符并不与此有任何关系。 - Michael Borgwardt
啊,我不知道字面量被内部化了。我原以为除非你明确调用.intern,否则没有字符串字面量被内部化。无论如何,在这种情况下,内部化的额外开销和空字符串(什么也没有)的额外开销都是必要的...我们都同意这一点。 - Malaxeur
确实只会创建一个空字符串的实例,但这仍然是浪费了一个字符串的创建。嗯,在一个非平凡的程序中,你可能会在某个地方为某些东西创建一个空字符串。 - Jay
显示剩余2条评论

3

不考虑任何性能问题,我认为第一种变体真的很丑陋。在我看来,这种“动态转换”在Java中甚至是可能的,这是一种耻辱。


1

是的,我认为这是一种不好的做法。

这将需要进行内存分配(除非编译器和/或JIT对它们进行了优化)。更重要的是,这将使得代码试图做什么变得不太明显。


0
直接想到的是,在第一个示例中将创建比第二个示例更多的String对象(以及一个额外的StringBuilder来执行连接)。
但你实际上要做的是从int创建一个String对象,而不是将String与int连接起来,所以使用:
String.valueOf(...); 

选项,

所以,是的,你的第一个选项是不好的做法!


Integer.valueOf(int i) 返回的是 Integer,而不是 String - Kip
谢谢 Kip。我匆忙中打败 Skeet 的时候,输错了。现已修正。 - Ron Tuffin

0
个人而言,我不喜欢使用"" + i这种风格,但这只是一种偏好/编码标准的问题。理想情况下,编译器会将它们优化为等效的代码(尽管您必须反编译才能确定它是否真的这样做),但从技术上讲,在没有优化的情况下,"" + i更加低效,因为它创建了一个不必要的StringBuilder对象。

0

我想知道对于编译时常量,静态final变量哪种最好:

public static final int VIEW_TYPE_LABEL_FIELD = 1;
public static final int VIEW_TYPE_HEADER_FIELD = ;

...

List <String[]> listViewInfo = new ArrayList<>();

listViewInfo.add(new String[]{"Label/Field view", String.valueOf(VIEW_TYPE_LABEL_FIELD)});
listViewInfo.add(new String[]{"Header/Field view", "" + VIEW_TYPE_LABEL_FIELD});

编译器可以将字符串表达式替换为常量。哪个更容易被识别为编译时常量?也许对于("" + ..)结构更容易一些?

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