在StringBuffer追加中使用字符而不是String来表示单字符值

Zee*_*han 11 java string optimization string-concatenation pmd

我正在通过PMD规则AppendCharacterWithChar.它说避免在StringBuffer.append中将字符串联为字符串.

StringBuffer sb = new StringBuffer();
  // Avoid this
  sb.append("a");

  // use instead something like this
  StringBuffer sb = new StringBuffer();
  sb.append('a');
Run Code Online (Sandbox Code Playgroud)

我真的需要这个PMD规则吗?以下两段代码之间有很大的性能差异吗?

String text = new StringBuffer().append("some string").append('c').toString();

String text = new StringBuffer().append("some string").append("c").toString();
Run Code Online (Sandbox Code Playgroud)

icz*_*cza 13

将一个字符附加为一个char将永远比将其添加为一个更快String.

但性能差异是否重要?如果你只做一次,它就不会.如果它在一个循环内重复它的身体一百万次,那么是的,它可能很重要.

如果您已在编译时拥有该字符,则只需将其作为字符附加.如果它存储在一个带有String类型的变量中,请不要费心访问它,例如用String.charAt(0)其他方式,只需添加即可String.

在旁注:

赞成StringBuilder上课StringBuffer.StringBuilder更快,因为它的方法不同步(在大多数情况下你不需要).

在旁注#2:

这不会编译:

String text = new StringBuffer().append("some string").append('c');
Run Code Online (Sandbox Code Playgroud)

append()StringBuffer链接返回.你需要打电话toString():

String text = new StringBuffer().append("some string").append('c').toString();
Run Code Online (Sandbox Code Playgroud)


ass*_*ias 5

出于好奇,我使用 jmh 运行了一个微基准测试(包括 GC 监控)。使用字符串稍微慢一些,但差异很小:每次调用大约 5 ns(纳秒),并且 GC 活动没有显着差异。

\n\n

如果您调用的次数append("c")不是append(\'c\')一百万次,则会给您的程序增加 5 毫秒。

\n\n

基准测试结果,包括 gc 时间 -n表示 StringBuilder 的初始长度:

\n\n
Benchmark                             (n)  Mode  Cnt     Score     Error   Units\nSO28344.appendChar                      0  avgt   30    16.476 \xc2\xb1   0.331   ns/op\nSO28343294.appendChar:\xc2\xb7gc.time          0  avgt   30   256.000                ms\nSO28343294.appendString                 0  avgt   30    22.048 \xc2\xb1   0.345   ns/op\nSO28343294.appendString:\xc2\xb7gc.time        0  avgt   30   220.000                ms\n\nSO28343294.appendChar                  50  avgt   30    17.323 \xc2\xb1   0.967   ns/op\nSO28343294.appendChar:\xc2\xb7gc.time         50  avgt   30    67.000                ms\nSO28343294.appendString                50  avgt   30    20.944 \xc2\xb1   1.466   ns/op\nSO28343294.appendString:\xc2\xb7gc.time       50  avgt   30    74.000                ms\n\nSO28343294.appendChar                1000  avgt   30    58.396 \xc2\xb1   0.811   ns/op\nSO28343294.appendChar:\xc2\xb7gc.time       1000  avgt   30    25.000                ms\nSO28343294.appendString              1000  avgt   30    64.572 \xc2\xb1   4.779   ns/op\nSO28343294.appendString:\xc2\xb7gc.time     1000  avgt   30    24.000                ms\n
Run Code Online (Sandbox Code Playgroud)\n\n

代码:

\n\n
@State(Scope.Thread)\n@BenchmarkMode(Mode.AverageTime)\npublic class SO28343294 {\n\n  @Param({"0", "50", "1000"}) int n;\n  Random r = new Random();\n  StringBuilder sb;\n  String s;\n  char c;\n\n  @Setup(Level.Invocation) public void populate() {\n    sb = new StringBuilder(n + 5);\n    for (int i = 0; i < n; i++) {\n      sb.append((char) (r.nextInt(26) + \'a\'));\n    }\n    c = (char) (r.nextInt(26) + \'a\');\n    s = new String(new char[] { c });\n  }\n\n  @Benchmark public StringBuilder appendString() {\n    return sb.append(s);\n  }\n\n  @Benchmark public StringBuilder appendChar() {\n    return sb.append(c);\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n