10

选项1:

String newStr = someStr + 3 + "]";

选项 2:

String newStr = someStr + "3" + "]";

哪个选项在性能、内存和一般实践方面更好?我可以使用哪些推荐的工具/方法来测量我的代码的内存使用情况及其性能(除了测量开始时间和结束时间并计算差异)

4

5 回答 5

11

第一个将变为:

StringBuilder sb = new StringBuilder (String.valueOf (someStr));
sb.append (3);
sb.append ("]");
String newStr = sb.toString ();

第二个将变为:

StringBuilder sb = new StringBuilder (String.valueOf (someStr));
sb.append ("3");
sb.append ("]");
String newStr = sb.toString ();

下面是拆解:

public String foo (String someStr)
{
    String newStr = someStr + 3 + "]";
    return newStr;
}

public String bar (String someStr)
{
    String newStr = someStr + "3" + "]";
    return newStr;
}

public java.lang.String foo(java.lang.String);
Code:
   0: new           #16                 // class java/lang/StringBuilder
   3: dup
   4: aload_1
   5: invokestatic  #18                 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
   8: invokespecial #24                 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
  11: iconst_3
  12: invokevirtual #27                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
  15: ldc           #31                 // String ]
  17: invokevirtual #33                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  20: invokevirtual #36                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
  23: astore_2
  24: aload_2
  25: areturn

public java.lang.String bar(java.lang.String);
Code:
   0: new           #16                 // class java/lang/StringBuilder
   3: dup
   4: aload_1
   5: invokestatic  #18                 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
   8: invokespecial #24                 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
  11: ldc           #44                 // String 3
  13: invokevirtual #33                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  16: ldc           #31                 // String ]
  18: invokevirtual #33                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  21: invokevirtual #36                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
  24: astore_2
  25: aload_2
  26: areturn
于 2013-02-08T23:13:46.873 回答
7

两者之间不会有任何明显的区别。使用您认为最符合逻辑和可读性的内容。我会用

String newStr = someStr + "3]";
于 2013-02-08T23:11:47.627 回答
3

我会推荐Jprofiler作为一个很棒的 Java 应用程序分析工具,它可以帮助我发现很多内存问题。

我不认为选项 1 和 2 在内存使用方面有很大差异,尤其是对于桌面应用程序。

于 2013-02-08T23:12:05.973 回答
2

假设 someString 是常量,两者都是常量表达式,并且将在编译时进行评估。它们将产生相同的类文件和运行时行为。

资料来源:Java 语言规范写道:

编译时常量表达式是表示原始类型值或字符串的表达式,它不会突然完成并且仅使用以下内容组成:

  • 原始类型的文字和字符串类型的文字(§3.10.1、§3.10.2、§3.10.3、§3.10.4、§3.10.5)

  • 加法运算符+-(§15.18)

  • ...

使用 String.intern 方法,String 类型的编译时常量表达式始终是“内部”的,以便共享唯一的实例。

如果 someString 不是常量,大多数现代编译器将使用 StringBuilder,这是Java 语言规范明确允许的:

字符串连接的结果是对 String 对象的引用,该对象是两个操作数字符串的连接。在新创建的字符串中,左侧操作数的字符在右侧操作数的字符之前。

String 对象是新创建的(第 12.5 节),除非表达式是编译时常量表达式(第 15.28 节)。

实现可以选择在一个步骤中执行转换和连接,以避免创建然后丢弃中间 String 对象。为了提高重复字符串连接的性能,Java 编译器可以使用 StringBuffer 类或类似技术来减少通过计算表达式创建的中间字符串对象的数量。

对于原始类型,实现还可以通过直接从原始类型转换为字符串来优化包装对象的创建。

于 2013-02-08T23:16:39.013 回答
0

每当您连接一个字符串时,在每次连接时,您都会创建该字符串的一个新副本,并且两个字符串都会被复制,一次一个字符。这导致时间复杂度为 O(n 2 ) (McDowell)。

如果要提高性能,请使用

StringBuilder

它的构造函数之一具有以下语法:

public StringBuilder(int size); //Contains no character. Initial capacity of 'size'. 

StringBuilder(可变的字符序列。记住字符串是不可变的)通过简单地创建一个包含所有字符串的可调整大小的数组来帮助解决这个问题。仅在必要时将它们复制回字符串(McDowell)。

StringBuilder str = new StringBuilder(0);
str.append(someStr);
str.append(3);
str.append("]");

参考:

麦克道威尔,盖尔·拉克曼。破解编码访谈,第 6 版。打印。

“字符串生成器(Java 平台 SE 8)”。Docs.oracle.com。Np,2016 年。网络。2016 年 6 月 4 日。

于 2016-06-04T15:15:41.097 回答