pkslow.com 南瓜慢说

  • AllArticles
  • Container
  • Spring
  • Life
  • Cloud
  • Collections
  • About
  • GitHub

  • Search
Terraform101 English Terraform Middleware config Go Private Kubernetes pkslow Test HTTPS Redis Docker Mac Plan Stream MongoDB Spring DevOps JVM String Map Set List Performance Email Springboot JavaCollections ArrayList Java

判断String是否包含子串的四种方法及性能对比

Created on: 2020-03-10 | Category: Java | 0 | View: 600

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

实际上,String的contains方法是通过调用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代表不存在也不是一件容易的事。

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


Code for all: GitHub

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

file

Recommendations:
Cloud Native
Terraform
Container: Docker/Kubernetes
Spring Boot / Spring Cloud
Https
如何制定切实可行的计划并好好执行

  • Author 作者: LarryDpk 南瓜慢说
  • Link 链接: https://www.pkslow.com/archives/string-contains-performance
  • 版权声明: 本博客所有文章除特别声明外,不可转载!
# Terraform101 # English # Terraform # Middleware # config # Go # Private # Kubernetes # pkslow # Test # HTTPS # Redis # Docker # Mac # Plan # Stream # MongoDB # Spring # DevOps # JVM # String # Map # Set # List # Performance # Email # Springboot # JavaCollections # ArrayList # Java
Terraform101 English Terraform Middleware config Go Private Kubernetes pkslow Test HTTPS Redis Docker Mac Plan Stream MongoDB Spring DevOps JVM String Map Set List Performance Email Springboot JavaCollections ArrayList Java
示例讲解PostgreSQL表分区的三种方式
《Terraform 101 从入门到实践》 第一章 Terraform初相识
  • Contents
  • Site Overview
南瓜慢说

南瓜慢说

多年Java开发,主要专注后端技术:Java/Spring/Springboot/微服务/大数据等。

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

241 Posts
9 Categories
30 Tags
RSS
0%
© 2020 — 2022 南瓜慢说 pkslow The WebSite keeping alive:   粤ICP备20036375号