如何在大型Java代码库中找到所有天真(“+”)字符串连接?

时间:2009-06-16 20:41:51

标签: java optimization string

我们有一个庞大的代码库,我们怀疑在代码中有很多基于“+”的字符串连接可能会受益于StringBuilder / StringBuffer的使用。有没有一种有效的方法或现有工具来搜索这些,特别是在Eclipse中?

搜索“+”不是一个好主意,因为代码中有很多数学,所以这需要实际分析代码和类型以确定哪些添加涉及字符串。

11 个答案:

答案 0 :(得分:13)

我很确定FindBugs可以检测到这些。如果没有,它仍然非常有用。

编辑:确实可以找到concatenations in a loop,这是它真正发挥作用的唯一时间。

答案 1 :(得分:12)

确保您真正了解实际更好地使用StringBuilder的位置。我不是说你知道,但肯定有很多人会采用这样的代码:

String foo = "Your age is: " + getAge();

并将其转换为:

StringBuilder builder = new StringBuilder("Your age is: ");
builder.append(getAge());
String foo = builder.toString();

这只是同一件事的不太可读的版本。天真的解决方案通常是最佳解决方案。同样有些人担心:

String x = "long line" + 
    "another long line";

实际上在编译时执行连接。

正如纳桑德所说的那样,先找出你是否有问题......

答案 2 :(得分:10)

为什么不使用分析器来查找实际上重要的“天真”字符串连接?如果确实需要,只能切换到更详细的StringBuffer。

答案 3 :(得分:3)

你有可能成为performance worse and your code less readable。编译器已经进行了这种优化,除非你处于循环中,否则它通常会做得更好。此外,在JDK 8中,它们可能会出现StringUberBuilder,并且所有使用StringBuilder的代码运行速度都会变慢,而“+”连接字符串将从新类中受益。

  

“我们应该忘记小的效率,大约97%的时间说:过早的优化是所有邪恶的根源。然而,我们不应该放弃那个关键的3%的机会。“ - 唐纳德克努特

答案 4 :(得分:2)

IntelliJ可以使用“结构搜索”找到它们。您搜索“$ a + $ b”并将$ a和$ b的特征设置为java.lang.String类型。

但是,如果你有IntelliJ,它可能有一个内置的检查,可以更好地找到你想要的东西。

答案 5 :(得分:2)

我建议使用分析器。这确实是一个性能问题,如果您无法使用合理的测试数据显示代码,则更改它的可能性不大。

答案 6 :(得分:2)

Jon Skeet(一如既往)和其他人已经说过了所有需要但我真的想强调的是,也许你正在寻找一种不存在的性能提升......

看看这段代码:

public class StringBuilding {
  public static void main(String args[]) {
    String a = "The first part";
    String b = "The second part";
    String res = a+b;

    System.gc(); // Inserted to make it easier to see "before" and "after" below

    res = new StringBuilder().append(a).append(b).toString();
  }
}

如果你编译它并用javap反汇编它,这就是你得到的。

public static void main(java.lang.String[]);
  Code:
   0:   ldc     #2; //String The first part
   2:   astore_1
   3:   ldc     #3; //String The second part
   5:   astore_2
   6:   new     #4; //class java/lang/StringBuilder
   9:   dup
   10:  invokespecial   #5; //Method java/lang/StringBuilder."<init>":()V
   13:  aload_1
   14:  invokevirtual   #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   17:  aload_2
   18:  invokevirtual   #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   21:  invokevirtual   #7; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   24:  astore_3
   25:  invokestatic    #8; //Method java/lang/System.gc:()V
   28:  new     #4; //class java/lang/StringBuilder
   31:  dup
   32:  invokespecial   #5; //Method java/lang/StringBuilder."<init>":()V
   35:  aload_1
   36:  invokevirtual   #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   39:  aload_2
   40:  invokevirtual   #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   43:  invokevirtual   #7; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   46:  astore_3
   47:  return

如你所见,6-21与28-43完全相同。没有太多的优化,对吗?

编辑:循环问题虽然有效......

答案 7 :(得分:1)

不是只搜索 + 搜索“+ +”,而是可能会找到绝大多数。你连接多个变量的情况将更加困难。

答案 8 :(得分:1)

如果你有庞大的代码库,你可能有很多热点,可能会或可能不会涉及“+”连接。只需运行你通常的探查器,并修复大的探测器,无论它们是什么类型的构造。

修复一类(潜在)瓶颈并不是修复实际的瓶颈,这是一种奇怪的方法。

答案 9 :(得分:0)

使用PMD,您可以使用XPath或使用Java语法编写规则。可能值得研究它是否可以匹配字符串连接运算符 - 它肯定似乎属于静态分析的范围。这是一个模糊的想法,我将打造这个“社区维基”;如果有其他人想要详细说明(或按照这些方式创建自己的答案),请做!

答案 10 :(得分:0)

忘掉它 - 你的JVM很可能已经这样做了 - 见the JLS, 15.18.1.2 Optimization of String Concatenation

  

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