我有一个遗留Java文件,它使用字符串连接来构建巨大的String对象。这是一个严重的性能问题。是否有这样的方法,它执行以下操作
String test="I am a very bad programmer"
+"to use concatenation"
+"Instead of StringBuilder"
+" or StringBuffer";
到
StringBuilder strBuilder= new StringBuilder();
strBuilder.append("I am a bad programmer");
strBuilder.append("to use concatenation");
strBuilder.append("Instead of StringBuilder");
strBuilder.append(" or StringBuffer");
String str= strBuilder.toString();
基本上我需要java中的存根只是为了将String实例化作为输入并转换为StringBuilder.Anybody过去尝试过这个吗?
答案 0 :(得分:12)
不,这不是性能问题。如果您将字符串内联(就像您显示的那样)而不是使用循环,那么编译器会自动将+
转换为使用StringBuilder
。查看java.lang.String
Java语言为字符串连接运算符(+)提供特殊支持,并为其他对象转换为字符串。字符串连接是通过StringBuilder(或StringBuffer)类及其append方法实现的。字符串转换是通过方法toString实现的,由Object定义并由Java中的所有类继承。有关字符串连接和转换的其他信息,请参阅Gosling,Joy和Steele,Java语言规范。
更进一步 - 编译器可能会使用这些都是字符串常量的事实,甚至在运行之前就加入它们(JLS references)
答案 1 :(得分:9)
在您的示例中,固定文字比使用StringBuilder更有效。
编译器将检测到固定的文字,并将内联为单个值,因此两行
String s = "one" + "two" + "three";
和
String s = "onetwothree";
将生成完全相同的字节码。
如果连接不是使用文字而是使用函数调用,则图片是不同的。
当你需要动态追加字符串时,更喜欢StringBuilder而不是StringBuffer,因为它不会同步,因为它稍快一些。
以下是字节码示例:
public class Test { private String s = "one" + "two" + "three"; } public class Test2 { private String s2 = "onetwothree"; }
这些类的生成字节码是:
c:\Temp>javap -c Test Compiled from "Test.java" public class Test extends java.lang.Object{ public Test(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()V 4: aload_0 5: ldc #2; //String onetwothree 7: putfield #3; //Field s:Ljava/lang/String; 10: return } c:\Temp>javap -c Test2 Compiled from "Test2.java" public class Test2 extends java.lang.Object{ public Test2(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()V 4: aload_0 5: ldc #2; //String onetwothree 7: putfield #3; //Field s:Ljava/lang/String; 10: return }
正如您所看到的,两个变量的处理方式相同。
我不认为这属于语言规范,因为这只是“编译器优化”。
不同的编译器(我使用的是Sun编译器)可能会做一些完全不同的事情 - 只要行为没有改变就可以了。
答案 2 :(得分:4)
实际上,编译器已经在最新版本的Java中为您应用了该优化(至少从1.5开始,我认为)。
What happens when Java Compiler sees many String concatenations in one line?
http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.18.1.2
答案 3 :(得分:0)
只是常量字符串连接在编译时被优化,并且是微不足道的。问题是当你做一些不那么重要的事情时:
String example1 =“Prefix”+ variableString1 +“Suffix”;
最坏的情况是在每次迭代需要创建新字符串时附加的循环。因为这对缓冲的文件读取很常见,所以你可以重新创建非常大的字符串,这是我最近遇到的一个问题。
虽然我知道你为什么要做你做的事情,但是代码的结构太不同了,只是插入和替换,编辑代码的脚本必须非常先进才能处理所有参考文献。也许有一种方法可以使用自治内部类,但是可以让你保持相同的字符串引用,但是在字符串构建器中包含实际构造。它可能与优化者已经做过的事情没有什么不同