将长日志分为两个的性能问题

时间:2017-01-09 04:00:01

标签: java string concatenation

当我们将一长串代码分成两行以便于阅读时,它会在行之间引入一个加号(如果在文本之间分割)。 例如,在正在记录某些文本的文本中间拆分一条长行。

那么,如果它带来了额外的字符串连接,应该避免这种情况吗?或者更好的可读性权衡更高?

3 个答案:

答案 0 :(得分:2)

所有常见的Java编译器都太成熟了,无法像运行时连接字符串文字那样愚蠢。我们来看看吧。鉴于此代码:

public class CatStrings {
  public static void main(String [] args) {
    String a = "This is a long long long string broken up "
        + "into parts to see if the compiler "
        + "optimizes the concatenation.";
    System.out.println(a);
  }
}

我的Java 8编译器 - Oracle标准 - 做正确的事情,如javap输出所示:

  stack=2, locals=2, args_size=1
     0: ldc           #2                  // String This is a long long long string broken up into parts to see if the compiler optimizes the concatenation.
     2: astore_1
     3: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
     6: aload_1
     7: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
    10: return

答案 1 :(得分:1)

是的,会有一点点性能影响。常规编译器不进行任何优化。它只是用StringBuilder方法调用替换+运算符。例如。如果您有String s = "x" + "y" + "z";,则在编译为字节码之前,它可能会被String s = new StringBuilder().append("x").append("y").append("z");替换。但这里没有真正的优化。在生成字节代码之前,它不会用String s = "xyz";替换它。我不确定JIT编译器在生成本机处理器指令之前是否优化它。但即使它确实如此,它在运行时会导致性能受到轻微打击。

就个人而言,如果它们以微小的性能损失为代价,我会更加关注优雅和可读性。

答案 2 :(得分:1)

取决于。

如果只有常量,javac会处理它。以下程序:

public class Main {
    public static void main(String[] args) {
        System.out.println("foo"+"bar");
    }
}

变成以下字节码(删除了一些不相关的部分):

public class com/hazelcast/Main {

  // access flags 0x9
  public static main([Ljava/lang/String;)V
   L0
    LINENUMBER 9 L0
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    LDC "foobar"
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
   L1
    LINENUMBER 10 L1
    RETURN
   L2
    LOCALVARIABLE args [Ljava/lang/String; L0 L2 0
    MAXSTACK = 2
    MAXLOCALS = 1
}

你可以在那里看到foobar常数。因此,在这种情况下,没有性能损失。

但是,如果我们将程序更改为更现实的程序:

public class Main {

    public static void main(String[] args) {
        int a = 1;
        System.out.println(a+"foo" + "bar");
    }
}

我们得到以下字节码:

public class com/hazelcast/Main {

  // access flags 0x9
  public static main([Ljava/lang/String;)V
   L0
    LINENUMBER 9 L0
    ICONST_1
    ISTORE 1
   L1
    LINENUMBER 10 L1
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    NEW java/lang/StringBuilder
    DUP
    INVOKESPECIAL java/lang/StringBuilder.<init> ()V
    ILOAD 1
    INVOKEVIRTUAL java/lang/StringBuilder.append (I)Ljava/lang/StringBuilder;
    LDC "foo"
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
    LDC "bar"
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
    INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
   L2
    LINENUMBER 11 L2
    RETURN
   L3
    LOCALVARIABLE args [Ljava/lang/String; L0 L3 0
    LOCALVARIABLE a I L1 L3 1
    MAXSTACK = 3
    MAXLOCALS = 2
}

正如你所看到的,&#34; foo&#34;和&#34; bar&#34;不会自动连接。

我不知道JIT是否能够删除不需要的连接。