zoukankan      html  css  js  c++  java
  • 【Java必修课】判断String是否包含子串的四种方法及性能对比

    1 简介

    判断一个字符串是否包含某个特定子串是常见的场景,比如判断一篇文章是否包含敏感词汇、判断日志是否有ERROR信息等。本文将介绍四种方法并进行性能测试。

    2 四种方法

    2.1 JDK原生方法String.indexOf

    String的函数中,提供了indexOf(subStr)方法,返回子串subStr第一次出现的位置,如果不存在则返回-1。例子如下:

    //包含Java
    assertEquals(7, "Pkslow Java".indexOf("Java"));
    //如果包含多个,返回第一次出现位置
    assertEquals(0, "Java Java".indexOf("Java"));
    //大小写敏感
    assertEquals(-1, "Google Guava".indexOf("guava"));
    

    2.2 JDK原生方法String.contains

    最直观判断的方法是contains(subStr),返回类型为boolean,如果包含返回true,不包含则返回false。例子如下:

    //包含Java
    assertTrue("code in Java".contains("Java"));
    //大小写敏感,不包含GO
    assertFalse("Let's go".contains("GO"));
    //转为大写后包含
    assertTrue("Let's go".toUpperCase().contains("GO"));
    

    实际上,Stringcontains方法是通过调用indexOf方法来判断的,源码如下:

    public boolean contains(CharSequence s) {
      return indexOf(s.toString()) > -1;
    }
    

    2.3 JDK原生正则匹配Pattern

    通过强大的正则匹配来判断,虽然有点杀鸡用牛刀的感觉,但也不是不能用,例子如下:

    Pattern pattern = Pattern.compile("Java");
    //包含Java
    Matcher matcher1 = pattern.matcher("Python, Java, Go, C++");
    assertTrue(matcher1.find());
    //不包含Java
    Matcher matcher2 = pattern.matcher("Python, C, Go, Matlab");
    assertFalse(matcher2.find());
    

    2.4 Apache库StringUtils.contains

    Apache的commons-lang3提供许多开箱即用的功能,StringUtils就提供了许多与字符串相关的功能,例子如下:

    //包含sub
    assertTrue(StringUtils.contains("String subString", "sub"));
    //大小写敏感
    assertFalse(StringUtils.contains("This is Java", "java"));
    //忽略大小写
    assertTrue(StringUtils.containsIgnoreCase("This is Java", "java"));
    

    3 性能对比

    我们使用JMH工具来对四种方法进行性能测试,Maven引入代码如下:

    <dependency>
      <groupId>org.openjdk.jmh</groupId>
      <artifactId>jmh-core</artifactId>
      <version>${openjdk.jmh.version}</version>
    </dependency>
    <dependency>
      <groupId>org.openjdk.jmh</groupId>
      <artifactId>jmh-generator-annprocess</artifactId>
      <version>${openjdk.jmh.version}</version>
    </dependency>
    

    测试代码如下:

    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.NANOSECONDS)
    public class StringContainsPerformanceTest {
        @State(Scope.Thread)
        public static class MyState {
            private String text = "If you want to be smart; read. If you want to be really smart; read a lot.";
            Pattern pattern = Pattern.compile("read");
        }
    
        @Benchmark
        public int indexOf(MyState state) {
            return state.text.indexOf("read");
        }
    
        @Benchmark
        public boolean contains(MyState state) {
           return state.text.contains("read");
        }
    
        @Benchmark
        public boolean stringUtils(MyState state) {
            return StringUtils.contains(state.text, "read");
        }
    
        @Benchmark
        public boolean pattern(MyState state) {
            return state.pattern.matcher(state.text).find();
        }
    
        public static void main(String[] args) throws Exception {
            Options options = new OptionsBuilder()
                    .include(StringContainsPerformanceTest.class.getSimpleName())
                    .threads(6)
                    .forks(1)
                    .warmupIterations(3)
                    .measurementIterations(6)
                    .shouldFailOnError(true)
                    .shouldDoGC(true)
                    .build();
            new Runner(options).run();
        }
    }
    

    测试结果如下:

    Benchmark    Mode  Cnt    Score    Error  Units
    contains     avgt    6   11.331 ±  1.435  ns/op
    indexOf      avgt    6   11.250 ±  1.822  ns/op
    pattern      avgt    6  101.196 ± 12.047  ns/op
    stringUtils  avgt    6   29.046 ±  3.873  ns/op
    

    最快的就是indexOf方法,其次是contains方法,二者应该没有实际区别,contains是调用indexOf来实现的。Apache的StringUtils为第三方库,相对慢一些。最慢的是使用了正则的Pattern的方法,这不难理解,正则引擎的匹配是比较耗性能的。

    4 总结

    本文介绍了判断一个字符串是否包含某个特定子串的四种方法,并通过性能测试进行了对比。其中性能最好的是String的indexOf方法和contains方法,建议使用contains方法,性能好,跟indexOf相比,更直观,更不容易犯错。毕竟让每个人时刻记住返回-1代表不存在也不是一件容易的事。

    但是,使用indexOfcontains方法都需要注意做判空处理,这时StringUtils的优势就体现出来了。


    欢迎关注公众号<南瓜慢说>,将持续为你更新...

    file

    多读书,多分享;多写作,多整理。

  • 相关阅读:
    180322
    20180317
    C语言编译器
    PAT甲级_PAT Advanced Level 1002. A+B for Polynomials (25) C
    java中的装箱与拆箱
    PAT甲级_PAT Advanced Level 1002. A+B for Polynomials (25)
    Java(3)_Ideal 使用指南
    4.jmeter参数化实战
    1.jmeter搭建环境
    Python_异常机制及日志
  • 原文地址:https://www.cnblogs.com/larrydpk/p/12459386.html
Copyright © 2011-2022 走看看