简体   繁体   English

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

[英]Java performance String.indexOf(char) vs String.indexOf(single String)

I think String.indexOf(char) is a little more faster than String.indexOf(String) when using single character & single String(ex, 'x' & "x") 我认为当使用单个字符和单个字符串(例如,'x'和“x”)时, String.indexOf(char)String.indexOf(String)快一点

To make sure my guessing, I wrote easy test code like below. 为了确保我的猜测,我编写了简单的测试代码,如下所示。

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

}

alphabet is String variable that has "abcd...xyzABCD...XYZ". alphabet是具有“abcd ... xyzABCD ... XYZ”的字符串变量。

from this code, I got result table like this... 从这段代码中,我得到了这样的结果表......

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) looks like converge to 9ms, however String.indexOf(char) increases exponentially. String.indexOf(String)看起来像收敛到9ms,但是String.indexOf(char)呈指数增长。

I'm very confused. 我很困惑。 Is there any optimization for using String in this case? 在这种情况下是否有使用String的优化? Or how I figure out this result? 或者我如何弄清楚这个结果?


Update 更新

I ran jmh with below two benchmark method. 我用以下两种基准方法运行jmh。 Each method calls a indexOf method. 每个方法都调用一个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');
    }
}

result: 结果:

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

This result also show indexOf(String) is faster.. 这个结果也表明indexOf(String)更快..

I think that it is time to think about hidden optimization 我认为是时候考虑隐藏优化了

Any idea? 任何想法?

Your JMH test is incorrect as you don't consume the result, so the indexOf call can be (or can be not) removed at all by JIT compiler. 您的JMH测试不正确,因为您没有使用结果,因此JIT编译器可以(或可以不)删除indexOf调用。 In your case it seems that JIT-compiler determined that indexOf(String) has no side-effect and removed this call at all, but did not do the same for indexOf(char) . 在你的情况下,似乎JIT编译器确定indexOf(String)没有副作用并且完全删除了这个调用,但是对indexOf(char)没有做同样的事情。 Always consume the result (the simplest way is to return it from the benchmark). 总是消耗结果(最简单的方法是从基准测试返回)。 Here's my version: 这是我的版本:

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);
    }
}

I test the same thing, but added two indirect tests: when searched char or String is loaded from the field, thus its exact value is unknown during the JIT-compilation. 我测试了相同的东西,但添加了两个间接测试:当搜索char或从字段加载String时,因此在JIT编译期间其确切值是未知的。 The results are the following (Intel x64): 结果如下(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

As you can see, indexOfChar performs in the same way regardless of direct or indirect access. 如您所见,无论是直接访问还是间接访问, indexOfChar都以相同的方式执行。 The indexOfString is slightly faster for direct access, but somewhat slower for indirect. indexOfString对于直接访问来说稍微快一些,但对于间接访问来说稍慢一些。 That's because indexOf(String) is a JVM intrinsic: its Java code is actually replaced by JIT compiler with efficient inline implementation. 这是因为indexOf(String)是一个JVM内在函数:它的Java代码实际上被JIT编译器替换为高效的内联实现。 For constant string known at JIT compilation time it's possible to generate more efficient code. 对于在JIT编译时已知的常量字符串,可以生成更高效的代码。

In general there's no big difference at least for such short strings. 一般来说,至少对于这样的短字符串没有太大的区别。 Thus you may use either of these methods for single symbol match. 因此,您可以使用这些方法中的任何一种进行单符号匹配。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM