【Java必修课】判断String是否包含子串的四种方法及性能对比

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

实际上,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引入代码如下:

org.openjdk.jmh

jmh-core

${openjdk.jmh.version}

org.openjdk.jmh

jmh-generator-annprocess

${openjdk.jmh.version}

测试代码如下:

@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的优势就体现出来了。

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

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

相关推荐

2025年國際足總女子室內五人制足球世界盃
天天365彩票软件官方下载3D

2025年國際足總女子室內五人制足球世界盃

📅 09-04 👀 1893
钉钉版本区别
beat365官方网站

钉钉版本区别

📅 07-09 👀 1941
OPPO手机时间显示设置
beat365官方网站

OPPO手机时间显示设置

📅 07-11 👀 5971
【红米手机专区】报价 评测 导购 图片(Redmi)红米手机大全
APSCA介绍-专业社会责任审核员协会
best365官网登录入口

APSCA介绍-专业社会责任审核员协会

📅 08-08 👀 2865
电话系统有哪些主要设备组成?
beat365官方网站

电话系统有哪些主要设备组成?

📅 07-10 👀 4390
DNF游戏迅雷下载:快速便捷的游戏体验与安全须知
汽车之家
best365官网登录入口

汽车之家

📅 08-21 👀 8174
跳跳狗阴阳师哪里多-阴阳师跳跳狗出处一览
天天365彩票软件官方下载3D

跳跳狗阴阳师哪里多-阴阳师跳跳狗出处一览

📅 07-02 👀 9208