当前位置: 首页 > 面试题库 >

Java性能String.indexOf(char)与String.indexOf(单个String)

公孙威
2023-03-14
问题内容

我认为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测试不正确,因为您不使用该结果,因此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);
    }
}

我测试了同样的东西,但是增加了两个间接测试:从字段中加载搜索到的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编译时已知的常量字符串,可以生成更有效的代码。

通常,至少对于这样的短字符串没有太大的区别。因此,您可以将这些方法之一用于单个符号匹配。



 类似资料:
  • 问题内容: 我很好奇为什么在查询字符串中的空字符串索引时为什么返回0(而不是-1)。 Javadocs仅说此方法返回指定字符串在此字符串中的索引,如果找不到该字符串,则返回-1。 对我来说,这种行为似乎非常出乎意料,我本来希望为-1。有什么想法为什么这种意外行为会继续吗?我至少认为这值得在该方法的Javadocs中进行说明… 问题答案: 空字符串无处不在,无处不在。它始终存在于所有弦乐中,渗透着它

  • 问题内容: 我正在尝试解析一个字符串,我需要使用子字符串来做到这一点。该字符串包含撇号字符。我的问题是,如何使用temp来获取String.indexOf以获取撇号字符的索引? 问题答案: 您的变量名错误(是保留字),应使用转义符:

  • 问题内容: 我阅读的源代码,很惊讶地发现它不使用Knuth–Morris–Pratt算法?众所周知,KMP更有效。那么为什么不使用它呢? 我周围的人告诉我,对于短字符串KMP来说已经足够了,但是如果您需要性能并且打算与大字符串一起使用,则不是一个好选择。但是他没有告诉我细节。 所以,这是我的问题: 为什么我们不使用KMP ? 为什么KMP对于大字符串不是一个好选择? 问题答案: KMP在最坏情况下

  • 问题内容: 我想知道为什么当描述为char时indexOf方法的参数为int。 public int indexOf(int ch) http://download.oracle.com/javase/1,5.0/docs/api/java/lang/String.html#indexOf%28int%29 a]基本上,我感到困惑的是java中的int是32位,而unicode字符是16位。 b]

  • 问题内容: 我不了解String.index Of方法的行为。 为什么p 8而不是9的输出?句子中有9个P。 问题答案: 索引从零开始: 第 一个 是index 。 来自的javadoc : 返回 索引 的的 第一次出现 在该字符序列的字符的表示由该对象,或如果字符不会发生。

  • 本文向大家介绍算法练习之从String.indexOf的模拟实现开始,包括了算法练习之从String.indexOf的模拟实现开始的使用技巧和注意事项,需要的朋友参考一下 String.indexOf的模拟实现,没想象中有多么高深的查找算法,就是最普通的遍历查找 思路:先找到第一个相同的字符,然后依次比较后面的字符,若都相等则表示查找成功 同样更常用的String.contains方法实际上就是调