Java性能String.indexOf(char)vs String.indexOf(单个字符串)

par*_*ana 2 java string performance

我认为String.indexOf(char)String.indexOf(String)使用单个字符和单个字符串(例如,'x'和"x")快一点

为了确保我的猜测,我编写了简单的测试代码,如下所示.

public static void main(String[] args) {
    IndexOfTest test = new IndexOfTest(Integer.parseInt(args[0]));

    test.run();
}

public IndexOfTest(int loop) {
    this.loop = loop;
}

public void run() {
    long start, end;
    start = System.currentTimeMillis();
    for(int i = 0 ; i < loop ; i++) {
        alphabet.indexOf("x");
    }
    end = System.currentTimeMillis();
    System.out.println("indexOf(String) : " + (end - start) + "ms");

    start = System.currentTimeMillis();
    for(int i = 0 ; i < loop ; i++) {
        alphabet.indexOf('x');
    }
    end = System.currentTimeMillis();
    System.out.println("indexOf(char) : " + (end - start) + "ms");

}
Run Code Online (Sandbox Code Playgroud)

alphabet是具有"abcd ... xyzABCD ... XYZ"的字符串变量.

从这段代码中,我得到了这样的结果表......

loop     10^3  10^4  10^5  10^6  10^7

String      1     7     8     9     9

char        1     2     5    10    64
Run Code Online (Sandbox Code Playgroud)

String.indexOf(String)看起来像收敛到9ms,但是String.indexOf(char)呈指数增长.

我很困惑.在这种情况下是否有使用String的优化?或者我如何弄清楚这个结果?


更新

我用以下两种基准方法运行jmh.每个方法都调用一个indexOf方法.

@State(Scope.Thread)
public class MyBenchmark {
    private String alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

    @Benchmark
    public void indexOfString() {
        alphabet.indexOf("x");
    }

    @Benchmark
    public void indexOfChar() {
    alphabet.indexOf('x');
    }
}
Run Code Online (Sandbox Code Playgroud)

结果:

Benchmark                   Mode  Cnt           Score        Error  Units
MyBenchmark.indexOfChar    thrpt   30   142106399.525 ±  51360.808  ops/s
MyBenchmark.indexOfString  thrpt   30  2178872840.575 ± 864573.421  ops/s
Run Code Online (Sandbox Code Playgroud)

这个结果也表明indexOf(String)更快..

我认为是时候考虑隐藏优化了

任何的想法?

Tag*_*eev 10

您的JMH测试不正确,因为您没有使用结果,因此indexOfJIT编译器可以(或者可以不)删除该调用.在你的情况下,似乎JIT编译器确定indexOf(String)没有副作用并且完全删除了这个调用,但是没有做同样的事情indexOf(char).总是消耗结果(最简单的方法是从基准测试返回).这是我的版本:

import java.util.*;
import java.util.concurrent.TimeUnit;

import org.openjdk.jmh.annotations.*;

@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Fork(3)
public class IndexOfTest { 
    private String str;
    private char c;
    private String s;

    @Setup
    public void setup() {
        str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
        c = 'z';
        s = "z";
    }

    @Benchmark
    public int indexOfChar() {
        return str.indexOf('z');
    }

    @Benchmark
    public int indexOfString() {
        return str.indexOf("z");
    }

    @Benchmark
    public int indexOfCharIndirect() {
        return str.indexOf(c);
    }

    @Benchmark
    public int indexOfStringIndirect() {
        return str.indexOf(s);
    }
}
Run Code Online (Sandbox Code Playgroud)

我测试了相同的东西,但添加了两个间接测试:当搜索char或从字段加载String时,因此在JIT编译期间其确切值是未知的.结果如下(Intel x64):

# JMH 1.11.2 (released 27 days ago)
# VM version: JDK 1.8.0_45, VM 25.45-b02
Benchmark                          Mode  Cnt   Score   Error  Units
IndexOfTest.indexOfChar            avgt   30  25,364 ± 0,424  ns/op
IndexOfTest.indexOfCharIndirect    avgt   30  25,287 ± 0,210  ns/op
IndexOfTest.indexOfString          avgt   30  24,370 ± 0,100  ns/op
IndexOfTest.indexOfStringIndirect  avgt   30  27,198 ± 0,048  ns/op
Run Code Online (Sandbox Code Playgroud)

如您所见,indexOfChar无论是直接访问还是间接访问,都以相同的方式执行.该indexOfString是直接访问间接稍快一些,但略慢.那是因为它indexOf(String)是一个JVM内在的:它的Java代码实际上被JIT编译器替换为高效的内联实现.对于在JIT编译时已知的常量字符串,可以生成更高效的代码.

一般来说,至少对于这样的短字符串没有太大的区别.因此,您可以使用这些方法中的任何一种进行单符号匹配.

  • @David,当我尝试深入了解 JVM 开发人员的想法时,我得出的结论是,内在化 `indexOf(String)` 的主要原因是有机会为 [Boyer–Moore 算法](https:// /en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string-search_algorithm) 在具有常量参数的调用站点上,并将其保留以供后续调用。对于不可预测的、可能变化的论点,目前尚不清楚这样的准备工作是否会得到回报。而对于单个char字符串来说,无论如何也没有什么优势。因此,这种特殊情况的性能差异只是一个副作用 (2认同)