写Java的人几乎绕不开工具类,而围绕Apache Commons生态封装的ApacheUtils更是日常开发里的常客。不过很多初学者对它的认识比较零散,只知道能用,不清楚哪些方法高频、哪些场景该用哪个类,甚至因为方法名相近而误用。这篇文章把常用的工具方法按类整理一遍,配上可直接运行的代码示例,最后再总结几条容易踩的坑,帮你把这套工具用明白。

一、StringUtils:字符串处理的核心利器
StringUtils来自commons-lang3包,是使用频率最高的工具类之一。它最大的价值在于所有方法都是null安全的,调用StringUtils.isEmpty(str)时即使传入null也不会抛出空指针异常,这一点比直接调用字符串自身的str.equals()安全得多。
判断类方法是日常用得最多的:isEmpty判断是否为null或空串,isBlank在此基础上额外认为纯空格字符串也算空白,isNumeric判断是否全是数字。很多人分不清isEmpty和isBlank的区别,简单记:isBlank的条件更严格。比如StringUtils.isBlank(" ")返回true,而StringUtils.isEmpty(" ")返回false,在校验用户输入时通常应该用isBlank。
String str = " ";
StringUtils.isEmpty(str); // false,长度不为0
StringUtils.isBlank(str); // true,全是空格
StringUtils.isNotBlank("abc"); // true
StringUtils.trimToNull(" a "); // "a",全空白则返回null
StringUtils.defaultIfBlank(str, "默认值"); // 空白时返回默认值
StringUtils.abbreviate("这是一段很长的文本", 8); // 截断并加省略号
StringUtils.join(new String[]{"a","b","c"}, ","); // "a,b,c"
除了判断,拼接和截取也很实用。join方法可以把数组或集合按分隔符拼成字符串,比手写循环拼接简洁太多;abbreviate适合列表页展示超长标题时的省略处理;capitalize和uncapitalize则常用于驼峰命名的转换场景。需要注意旧版本的commons-lang2里这些方法在StringUtils下,而lang3做了拆分,引入依赖时要认准commons-lang3这个groupId。
二、CollectionUtils与MapUtils:集合判断的标配
集合判空是几乎所有业务代码都绕不开的操作。自己写list != null && !list.isEmpty()不仅啰嗦还容易漏掉一半条件,而CollectionUtils一行搞定,且天然防空指针。
List<String> list = null;
CollectionUtils.isEmpty(list); // true
CollectionUtils.isNotEmpty(list); // false
Map<String, Object> map = new HashMap<>();
MapUtils.isEmpty(map); // true
MapUtils.isNotEmpty(map); // false
// 常见配合:为空时给默认集合
List<String> safe = CollectionUtils.isEmpty(list)
? Collections.emptyList() : list;
除了判空,commons-collections4里的CollectionUtils还提供了集合运算能力,比如union求并集、intersection求交集、subtract求差集,处理权限对比、数据同步差异计算这类场景特别顺手。另外select和find方法支持传入Predicate做条件过滤,在老项目没有Stream API时是很好的替代方案。
需要提醒的是,commons-collections历史上出过著名的反序列化漏洞(CollectionUtils相关链),如果项目还在用3.x版本,建议尽快升级到commons-collections4并检查是否引入了额外的InvokerTransformer调用链,安全无小事。
三、IOUtils与FileUtils:流和文件操作的省心搭档
IOUtils来自commons-io包,主要解决流的读取、复制和关闭问题。写文件上传下载功能时,最经典的用法就是把输入流复制到输出流,一行代替原来十几行的循环读写加try-catch-finally。
// 文件下载:把网络流复制到响应输出流
try (InputStream in = new URL(fileUrl).openStream();
OutputStream out = response.getOutputStream()) {
IOUtils.copy(in, out);
} catch (IOException e) {
log.error("下载失败", e);
}
// 流转字符串,自动处理编码
String content = IOUtils.toString(in, StandardCharsets.UTF_8);
byte[] bytes = IOUtils.toByteArray(in);
// 静默关闭,不怕null也不抛异常
IOUtils.closeQuietly(in);
FileUtils则面向文件系统操作,readFileToString读整个文件为字符串,writeStringToFile把字符串写入文件,deleteDirectory递归删除目录,listFiles按扩展名枚举文件。生成临时报表后清理、按规则扫描配置目录,这些需求用它写起来非常干净。
// 读取整个文件
String text = FileUtils.readFileToString(
new File("C:\\test\\config.txt"), StandardCharsets.UTF_8);
// 递归删除临时目录
FileUtils.deleteDirectory(new File("C:\\temp\\report"));
// 列出目录下所有json文件(含子目录)
Collection<File> files = FileUtils.listFiles(
new File("C:\\data"), new String[]{"json"}, true);
// 复制目录
FileUtils.copyDirectory(new File("C:\\src"), new File("C:\\backup"));
有一点要特别注意:readFileToString会把整个文件加载进内存,处理大文件时千万别用它,否则一个几百兆的日志文件就能把堆内存打满。大文件场景应该改用FileUtils.lineIterator逐行读取,用完记得调用LineIterator.close()或者借助try-with-resources释放资源。
四、常见问题与注意事项
第一个高频问题是依赖冲突。commons-lang2和lang3的包名不同(前者是org.apache.commons.lang,后者是org.apache.commons.lang3),可以共存,但也因此容易导错包,编译不报错运行时才发现行为不一致。建议在IDE里配置好自动导入的排除规则,统一只用lang3。
第二个问题是方法误用。除了前面说的isEmpty与isBlank,还有IOUtils.copy与copyLarge的区别:copy在流超过2GB时会返回-1,处理大文件要选copyLarge。另外FileUtils.readFileToByteArray同样有内存风险,原则很简单,凡是一次性加载的方法都要先掂量数据量。
第三个问题是流资源泄漏。虽然closeQuietly很方便,但更推荐try-with-resources写法,让编译器保证关闭动作一定执行。工具类只是简化代码,不是替代资源管理规范,该有的关闭逻辑不能省,否则线上句柄泄漏排查起来相当痛苦。
最后给一条选型建议:如果项目已经引入了Hutool或Guava,很多能力它们也覆盖了,不必为了用一个方法强行再加依赖。工具类贵在用对而不是用多,把StringUtils、CollectionUtils、IOUtils、FileUtils这四个高频类的核心方法掌握扎实,日常开发八成的场景都能从容应对。
ApacheUtilsJava工具类Commons Lang修改时间:2026-09-16 15:24:50