Java 怎么判断字符串里是否包含某个字符或子串?附 3 种方法讲清楚

编程狮(w3cschool.cn) 2026-08-10 15:03:48 浏览数 (19)
反馈

想在 Java 里判断一个字符串是否包含某段内容,最常用的是 contains 方法,它直接返回 true 或 false,告诉你「有没有」。如果你还想知道「包含的内容出现在第几个位置」,或者要做模糊匹配,那就用 indexOf 或正则。本文会用代码示例讲清这三种字符串包含判断方法,并提醒大小写、空指针与性能这几个最容易踩的坑,帮你写对每一处判断,而不是凭感觉调方法。无论你做的是后台参数校验还是前端数据清洗,这层判断都绕不开。

一、为什么需要判断字符串包含

判断字符串包含,是 Java 里极高频的字符串操作。举几个每天都在发生的场景:校验用户输入的手机号里是否包含区号、检查上传的文件名里是否包含「.java」后缀、从日志里筛出包含「ERROR」的行、或者判断一段备注里是否出现了敏感词。这些问题本质上都是同一句话:「某某字符串里,有没有出现另一段字符串?」

在动手之前要先分清两个概念:字符子串。字符是单个符号,比如字母 a、汉字「中」;子串是连续的一段,比如「abc」是「xabcy」的子串。Java 里判断包含,不管是字符还是子串,用的都是同一套方法,区别只在于你传进去的是单个字符还是一个字符串。先把 Java 教程 里 String 类这一章过一遍,理解不可变字符串的特性,后面才不会写出「为什么原串没被改」这类疑问。

二、方法一:contains 方法(最常用)

contains 是判断字符串包含最直接的方式,它只回答「有没有」,不关心「在哪」:

String text = "Hello, w3cschool";
boolean has = text.contains("w3c");
System.out.println(has); // true


boolean hasJava = text.contains("Java");
System.out.println(hasJava); // false(区分大小写)

contains 接收一个 CharSequence 参数,你可以传字符串,也可以传单个字符(用单引号)。它返回 boolean,配合 if 语句就能做分支判断。这是日常 90% 场景的首选,因为它语义最清晰——读代码的人一眼就知道你在「判断是否包含」。

从实现角度看,contains 内部其实就是 indexOf(str) >= 0,所以它和 indexOf 走的是同一套底层逻辑,只是帮你省掉了「判断返回值是不是 -1」这一步。要特别注意:contains 区分大小写。「w3c」和「W3C」在它眼里是两个不同的东西。如果你的业务不关心大小写,比如搜索关键词时,就要先把两边都转成小写再判断,例如 text.toLowerCase().contains(keyword.toLowerCase())。不要省略这步,否则会出现「明明有却判断成没有」的诡异 bug。语法细节记不住,随时翻 Java 速查手册 查。顺带一提,contains 在常量字符串上 JVM 会做一定的内部优化,所以不必为了微性能牺牲可读性,优先写清楚最重要。

三、方法二:indexOf 方法(能拿到位置)

如果你不只想「知不知道有」,还想知道「在第几个位置」,那就用 indexOf。它返回子串第一次出现的位置下标(从 0 开始),找不到就返回 -1:

String text = "Hello, w3cschool";
int pos = text.indexOf("w3c");
System.out.println(pos); // 7


int notFound = text.indexOf("xyz");
System.out.println(notFound); // -1

因为「找不到」固定返回 -1,所以判断包含的写法就变成了 text.indexOf("w3c") >= 0。这种写法在老代码里非常常见,功能和 contains 等价,但多给了你位置信息——比如你想把匹配到的内容高亮,或者从那个位置往后截取,就得靠 indexOf。

indexOf 同样区分大小写,也有只找字符的 indexOf('c') 重载,以及指定从哪个下标开始找的 indexOf("w3c", 5)。后一个在「找第二个匹配」这类需求里很有用:先找到第一个位置,再从它之后继续找。和 contains 一样,它做严格相等比较,对基本类型可靠、对对象无效。遇到术语卡壳,编程词典 里有通俗解释。

四、方法三:matches 正则,以及大小写、空指针与性能注意

当「包含」的规则变复杂,比如「是否包含数字」「是否包含邮箱格式」「是否以 http 开头」,containsindexOf 就力不从心了,这时用 matches 配合正则表达式:

String text = "订单号12345已发货";
boolean hasDigit = text.matches(".*\\d.*");
System.out.println(hasDigit); // true

matches 的特点是要传一个完整匹配的正则,所以前后要加 .* 表示「前后可以有任意字符」,等价于「包含数字」。它功能最强,但代价也最大——正则引擎的解析开销比 contains 高很多。所以原则很明确:能用 contains 解决的,绝不用 matches;只有规则复杂到普通方法写不出时,才上正则。

关于性能,如果你在一个循环里反复用 contains 判断同一个长字符串,可以考虑先把字符串缓存起来,避免重复创建临时对象。绝大多数业务场景下这点开销可以忽略,不必过早优化,但写循环时心里要有数。最后提醒两个高频坑:一是判断前字符串可能为 null,要先判空(text != null && text.contains(...))否则抛 NullPointerException;二是 contains("") 对非空串永远返回 true(空串被认为处处包含),别拿它当「是否有内容」来判断。

实际项目里还有两个实用经验值得记。第一,如果要统计「某关键词在长文里出现了几次」,不要靠循环反复调用 contains——它只回答「至少一次」,不回答「几次」。正确做法是用 indexOf 从 0 开始循环位移计数,或者直接用 Apache Commons Lang 的 StringUtils.countMatches。第二,contains 对空白字符很敏感:「 w3c」前面有个空格,和「w3c」就不是同一个子串,做内容比对前最好先 trim() 去掉两端空白。把这两点记牢,判断字符串包含这件事基本就稳了。如果项目里这类判断特别多,不妨封装一个工具方法,把大小写归一和去空白统一收口,既减少重复代码,也避免有人在某一处漏掉 trim 而埋下 bug。

总结

判断字符串包含,记住三档选择:只想知「有没有」用 contains,最直观;还想知道「在哪」用 indexOf,能拿位置;规则复杂(含数字、含格式)才用 matches 正则。 三者都区分大小写,调用前记得统一大小写、判空、留意空串与空白陷阱,就能避开最常见的问题。

延伸学习

  • 想往 Java 方向深入,Java 开发方向 整理了从基础到进阶的学习路径。
  • 编程课程 里也有配套实战,可以拿真实项目练手。

常见问题

Q1:contains 和 indexOf 性能差很多吗?
日常使用差别可以忽略。indexOf 内部和 contains 走的是相近的逻辑,contains 本质上就是 indexOf(str) >= 0。真正拉开差距的是 matches 正则。

Q2:为什么 contains 对中文也有效?
因为 Java 的 String 内部以 Unicode 存储,无论是英文、中文还是 emoji,在 contains 眼里都是「字符序列」,判断逻辑完全一致。

Q3:判断包含时总是报空指针怎么办?
说明原字符串是 null。在判断前先判空,写成 text != null && text.contains("关键词"),或者先用 Optional 处理,就能避开 NullPointerException。

0 人点赞