判断字符串是否为空或仅含空白字符:Java 11+ 用 isBlank(),Java 8 及以前需 null 检查后 trim().isEmpty();substring() 在 Java 7u6 后改为复制数组防内存泄漏,Java 9 起优化为 O(1);split() 默认丢弃末尾空串,可用负 limit 保留;拼接优先用 String.join() 或 StringBuilder,避免循环中用 +。

如何判断字符串是否为空或只包含空白字符
用 isEmpty() 判断长度是否为 0,但要注意它不处理空格;真正安全的写法是先用 isBlank()(Java 11+)——它会把 "\t\n " 这类也算作“空白”。Java 8 及以前得手动写 str == null || str.trim().isEmpty(),但要注意 trim() 对 null 会抛 NullPointerException,所以必须先判空。
-
isEmpty():仅检查 length == 0,速度快,但对" "返回 false -
isBlank():Java 11 引入,内部调用chars().allMatch(Character::isWhitespace),兼容 Unicode 空白符(如 、 ) - 老版本替代方案务必写成
str != null && str.trim().isEmpty(),顺序不能反
为什么 substring() 在 Java 7u6 之后性能变差又变好
Java 7u6 前,substring() 复用原字符串的 char[] 数组,内存不释放(大字符串截一小段,原数组仍被引用);7u6 到 Java 8 中改成了「复制新数组」,解决内存泄漏但带来额外开销;Java 9 起改用 byte[] + 编码标记,substring() 再次变成 O(1) 时间且无共享数组风险。
- Java 8 下大量调用
substring()可能引发 GC 压力,尤其从长日志中反复提取字段时 - 如果确定子串生命周期短于原串,可考虑用
String.valueOf(charArray, offset, count)避免构造中间 String - 注意
substring(beginIndex, endIndex)的 endIndex 是「不包含」的,越界直接抛StringIndexOutOfBoundsException
split() 的坑:为什么 "a..b".split("\\.") 返回长度为 3 的数组
split() 默认丢弃末尾空字符串,但遇到连续分隔符时,中间的空串会被保留。上面例子中正则 "\." 匹配点号,"a..b" 拆成 ["a", "", "b"] —— 因为两个点号之间有长度为 0 的子串。
- 想连末尾空串也保留?加负数 limit:
"a.b.".split("\\.", -1)→["a", "b", ""] - 想彻底忽略所有空结果?自己过滤:
Arrays.stream(str.split("\\.")).filter(s -> !s.isEmpty()).toArray(String[]::new) - 注意
.、*、+等在正则里有特殊含义,必须转义,直接写"."会匹配任意字符
字符串拼接选 +、StringBuilder 还是 String.join()
编译期能确定的字面量拼接(如 "a" + "b" + "c")会被 javac 优化成单个常量;运行期变量拼接,简单两三个用 + 也没问题(JDK 9+ 的 StringConcatFactory 会自动转成 StringBuilder);但循环内拼接必须用 StringBuilder,否则每轮都新建对象。
立即学习“Java免费学习笔记(深入)”;
- 连接带分隔符的集合,优先用
String.join(", ", list),比手写循环 +StringBuilder更简洁且已做空值防护 -
StringBuilder.append()比+=快一个数量级(10k 次拼接测试),尤其在嵌套循环中 - 多线程环境别共用同一个
StringBuilder实例,没同步保障;需要线程安全就换StringBuffer,但代价是性能下降约 20%
null、是否区分 Unicode 字符(比如 length() 返回的是 UTF-16 code unit 数,不是真实字符数)、以及正则相关方法默认使用的是 JVM 默认编码还是平台无关逻辑。









