Java 性能 String.indexOf(char) 与 String.indexOf(single String)

标签 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");

}
字母表是具有“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
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');
    }
}
结果:
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
这个结果也表明 indexOf(String) 更快..
我认为是时候考虑隐藏优化了
任何的想法?

最佳答案

您的 JMH 测试不正确,因为您不使用结果,因此 indexOf JIT 编译器可以(或不能)完全删除调用。在您的情况下,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);
    }
}

我测试了同样的事情,但添加了两个间接测试:从字段加载搜索的 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

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

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

关于Java 性能 String.indexOf(char) 与 String.indexOf(single String),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33646781/

相关文章:

java - 使用比字符串内容更少的字符在 Java 中打印字符串

mysql - 缓慢的 MySQL 查询

java - 将对象的 ArrayLIst 转换为字符串二维数组

c# - 查找字符串中出现次数最多的单词 C#

Java有哪些数据结构?

java - 字符串声明 - 两种不同的类型,哪个更好?

objective-c - 小于 256 RAM iOS 设备的应用程序在启动时崩溃

c - 很多printf的副作用?

java - PDF 文件无法使用 servlet 和 jsp 在浏览器中打开

java - 生成事件的最佳实践?