Java 8:字符串连接操作会对性能产生重大影响

dgm*_*dgm 14 java java-8

我正在阅读Java-8中引入的新添加的现有功能.新增加到String类的一个简单特性是对我来说很安静 - 这就是String Join方法.

例:

String.join(" ", "AZY","BAX"); // returns AZY BAX
Run Code Online (Sandbox Code Playgroud)

为了好奇,我通过编写一个简单的java代码来检查这个功能的性能(执行时间)

public static void main(String[] args) {
    long start = System.nanoTime();
    String abc= String.join(" ,"AZY","BAX" … // joining 1000 words of size 3 char;
    long diff = System.nanoTime() - start;
    System.out.println(" Java 8 String Join " + diff);

     start = System.nanoTime();
    abc= "AZY"+"BAX"+"CBA"+ … // adding 1000 word of size 3 char;
    diff = System.nanoTime() - start;
    System.out.println(" Tranditional " + diff);

    start = System.nanoTime();
    new StringBuilder().append("AZY").append("BAX").appe… // appending 1000 word of size 3 char;
    diff = System.nanoTime() - start;
    System.out.println(" String Builder Append " + diff);

}
Run Code Online (Sandbox Code Playgroud)

结果对我来说并不那么令人兴奋(在neno sec的时间)

Java 8 String Join     1340114
Tranditional             59785
String Builder Append   102807
Run Code Online (Sandbox Code Playgroud)

复杂度为o(n) - 事实上它是(n*单个元素长度的大小)

其他性能指标(记忆等)我没有测量过.

我的问题是:

  1. 我的测量有什么不对(大多数时候我相信jdk家伙)
  2. 将"join"API添加到String类的目的是什么?
  3. 是否有可用的Java 8性能分析

Bor*_*der 47

首先要做的事情.这不是你如何微桌面Java

阅读如何在Java中编写正确的微基准测试?第一.你的号码完全不相关,所以让我们忽略它们.

看第二个例子:

abc= "AZY"+"BAX"+"CBA"+...
Run Code Online (Sandbox Code Playgroud)

这看起来像编译时常量给我.这String将在编译时连接,并且没有任何基准测试.这是一个无用的比较,因为它的整个点StringBuilder或者String.join是连接String不是编译时常量的s.

转而比较StringBuilderString.join.看一下源代码:

public static String join(CharSequence delimiter, CharSequence... elements) {
    Objects.requireNonNull(delimiter);
    Objects.requireNonNull(elements);
    // Number of elements not likely worth Arrays.stream overhead.
    StringJoiner joiner = new StringJoiner(delimiter);
    for (CharSequence cs: elements) {
        joiner.add(cs);
    }
    return joiner.toString();
}
Run Code Online (Sandbox Code Playgroud)

这使用了StringJoiner.甲StringJoiner简单地使用一个StringBuilder引擎盖下,所以这两个是相同的.

查看代码通常比尝试和基准性能更具信息性.即使你做正确的基准测试.

值得注意的是,你的第一个方法是,在"空间"上join加入1000 String秒.而您的StringBuilder方法只是将它们一起添加.这两个不一样.

String.join方法的要点是你可以这样做:

String.join(", ", "a", "b", "c") // result is "a, b, c"
Run Code Online (Sandbox Code Playgroud)

有了StringBuilder你必须添加更多的代码.

  • @dipankaj因为Java 8的重点是添加避免显式循环的方法并使用更多功能范例.`String.join`应该是`Stream.of(a,b,c).collect(Collectors.joining())`的快捷方式.如果你没有看到允许用户在一行代码而不是4中加入`String`的好处,那么就不要使用它... (21认同)
  • 还有另外一个区别.`String.join`是一个*varargs*方法,暗示在它开始工作之前,创建一个临时数组并用所有1000个String`引用填充,而问题中的`StringBuilder`等效只调用`append` 1000次. (3认同)