Apache 工具包(commons-io commons-lang3 )保姆介绍
引言
作为 Java 后端开发者,日常开发中总会遇到大量重复工作:字符串判空、日期格式化、文件读写、参数校验…… 这些操作原生 API 要么代码繁琐,要么容易踩坑(比如空指针、流未关闭)。而 Apache Commons 工具包(尤其是commons-lang3和commons-io)就像 “效率加速器”,把这些常用操作封装成了简洁、安全的静态方法,一行代码就能搞定。
一、工具包整体介绍
1. 为什么要学这两个工具包?
- commons-lang3:专注于 “业务核心处理”,解决字符串、日期、对象、参数校验等高频问题,覆盖 80% 的业务代码场景。
- commons-io:专注于 “文件 / 流处理”,简化文件读写、复制、上传下载等操作,避免原生 API 的繁琐代码和资源泄露问题。
- 适用场景:接口参数校验、日期格式化(如有效期)、自测报告生成(文件读写)、配置文件读取、文件上传下载等。
2. 依赖引入(SpringBoot 项目直接用)
无需手动下载 jar 包,在pom.xml中添加以下依赖即可(版本稳定兼容,放心使用):
<!-- commons-lang3:字符串、日期、校验核心工具 -->
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.14.0</version>
</dependency><!-- commons-io:文件/流处理工具 -->
<dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.15.1</version>
</dependency>
添加后右键项目 → Maven → Reload Project,IDEA 会自动下载依赖。
二、核心方法速查(实战场景绑定)
(一)commons-lang3 核心方法
1. StringUtils(字符串处理:解决原生 String 的所有坑)
原生 String 的痛点:null判空会空指针、isEmpty()不识别纯空格、拼接集合繁琐。StringUtils全部搞定,业务中优先用!
| 方法名 | 作用 | 礼品卡业务场景 | 代码示例 |
|---|---|---|---|
| isBlank(String str) | 判断 null / 空串 / 纯空格(最常用) | 卡号、手机号、用户姓名非空校验 | if (StringUtils.isBlank(giftCardNo)){ throw new IllegalArgumentException("卡号不能为空")}; |
| isNotBlank(String str) | 反向判断(非空非空格) | 条件查询时判断参数是否有效 | if (StringUtils.isNotBlank(keyword)) { // 执行模糊查询 } |
| join(Collection coll, String sep) | 拼接集合为字符串 | 标签拼接(如 ["满减","无门槛"]→"满减,无门槛") | List<String> tags = Arrays.asList("满减","无门槛"); String tagStr = StringUtils.join(tags, ","); |
| substring(String str, int start, int end) | 截取字符串 | 从卡号提取前缀(如 GC202405201→GC2024) | String prefix = StringUtils.substring(giftCardNo, 0, 6); |
| trimToNull(String str) | 去空格,空则返回 null | 处理用户输入的模糊查询关键词 | String keyword = StringUtils.trimToNull(userInput); |
| length(String str) | 安全获取长度(null 返回 0) | 校验卡号长度(如必须 11 位) | Validate.isTrue(StringUtils.length(giftCardNo) == 11, "卡号必须为11位"); |
2. DateUtils(日期处理:线程安全 + 简洁)
原生SimpleDateFormat线程不安全,手动计算日期繁琐,DateUtils+FastDateFormat(线程安全)是最优解。
| 方法名 | 作用 | 礼品卡业务场景 | 代码示例 |
|---|---|---|---|
| addDays(Date date, int days) | 日期加天数 | 计算有效期(创建时间 + 90 天) | Date expireDate = DateUtils.addDays(new Date(), 90); |
| addMonths(Date date, int months) | 日期加月数 | 长期礼品卡有效期(+6 个月) | Date expireDate = DateUtils.addMonths(new Date(), 6); |
| isAfterNow(Date date) | 判断日期是否在当前时间之后 | 校验礼品卡是否未过期 | boolean isExpired = DateUtils.isAfterNow(expireDate); |
| isBeforeNow(Date date) | 判断日期是否在当前时间之前 | 校验有效期是否早于当前时间(非法参数) | Validate.isTrue(!DateUtils.isBeforeNow(expireDate), "有效期不能早于当前时间"); |
| parseDate(String str, String... formats) | 字符串转 Date | 前端传入有效期字符串转 Date | Date inputExpire = DateUtils.parseDate("2024-12-31", "yyyy-MM-dd"); |
补充:
FastDateFormat线程安全,全局复用:private static final FastDateFormat DATETIME_FORMATTER = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss"); String createTime = DATETIME_FORMATTER.format(new Date()); // 格式化创建时间
3. ObjectUtils(对象处理:安全判空)
处理实体类、集合、数组的判空,比null == obj覆盖场景更全。
| 方法名 | 作用 | 礼品卡业务场景 | 代码示例 |
|---|---|---|---|
| isEmpty(Object obj) | 判断对象 / 集合 / 数组是否为 null / 空 | 校验礼品卡实体、查询列表是否为空 | if (ObjectUtils.isEmpty(giftCard)) throw new RuntimeException("礼品卡不存在"); |
| isNotEmpty(Object obj) | 反向判断(非空) | 处理查询结果(非空则返回数据) | if (ObjectUtils.isNotEmpty(giftCardList)) { return giftCardList; } |
| defaultIfNull(T obj, T defaultObj) | 空则返回默认值 | 礼品卡默认金额(null 则返回 10 元) | BigDecimal amount = ObjectUtils.defaultIfNull(giftCard.getAmount(), new BigDecimal("10")); |
4. Validate(参数校验:替代繁琐 if-else)
集中处理参数校验,不符合条件直接抛异常,代码更简洁,错误信息更统一。
| 方法名 | 作用 | 礼品卡业务场景 | 代码示例 |
|---|---|---|---|
| notNull(Object obj, String msg) | 校验对象非 null,否则抛异常 | 校验金额、有效期等核心参数非 null | Validate.notNull(giftCard.getAmount(), "金额不能为空"); |
| isTrue(boolean condition, String msg) | 校验条件为 true,否则抛异常 | 校验金额 > 0、卡号长度 = 11 位 | Validate.isTrue(amount.compareTo(BigDecimal.ZERO) > 0, "金额必须大于0"); |
| notBlank(String str, String msg) | 校验字符串非空非空格(3.8 + 版本) | 简化卡号非空校验(无需额外调用 StringUtils) | Validate.notBlank(giftCardNo, "卡号不能为空"); |
(二)commons-io 核心方法
1. FileUtils(文件处理:一行搞定文件读写 / 复制)
原生文件操作需要处理创建文件、目录、关流等问题,FileUtils自动处理,还能避免异常。
| 方法名 | 作用 | 礼品卡业务场景 | 代码示例 |
|---|---|---|---|
| writeStringToFile(File file, String content, String encoding) | 字符串写入文件(自动创建文件) | 生成自测报告、导出礼品卡列表 | File report = new File("gift_card_test_report.txt"); FileUtils.writeStringToFile(report, content, "UTF-8"); |
| readFileToString(File file, String encoding) | 读取文件为字符串 | 读取配置文件、自测报告内容 | String reportContent = FileUtils.readFileToString(report, "UTF-8"); |
| readLines(File file, String encoding) | 按行读取文件 | 读取批量导入的礼品卡卡号文件 | List<String> cardNos = FileUtils.readLines(new File("import.txt"), "UTF-8"); |
| copyFileToDirectory(File src, File destDir) | 复制文件到目录(自动创建目录) | 备份自测报告、复制 Excel 导入模板 | FileUtils.copyFileToDirectory(report, new File("backup")); |
| deleteQuietly(File file) | 安静删除文件(不存在也不抛异常) | 删除过期临时文件 | FileUtils.deleteQuietly(new File("temp.txt")); |
2. IOUtils(流处理:避免资源泄露)
处理InputStream/OutputStream时,原生 API 需要手动关流,IOUtils自动关闭,还能简化复制、流转字符串等操作。
| 方法名 | 作用 | 礼品卡业务场景 | 代码示例 |
|---|---|---|---|
| copy(InputStream in, OutputStream out) | 复制流(自动处理缓冲区) | 上传礼品卡图片、下载模板文件 | IOUtils.copy(new FileInputStream("template.xlsx"), new FileOutputStream("target.xlsx")); |
| closeQuietly(Closeable closeable) | 安静关闭流(报错不抛异常) | 关闭文件流(避免资源泄露) | IOUtils.closeQuietly(inputStream); IOUtils.closeQuietly(outputStream); |
| toString(InputStream in, String encoding) | 流转字符串 | 读取 HTTP 请求流中的参数 | String requestBody = IOUtils.toString(request.getInputStream(), "UTF-8"); |
3. FilenameUtils(文件名处理:兼容不同系统)
解决 Windows/Linux 路径分隔符差异(\和/)、文件名提取、后缀判断等问题。
| 方法名 | 作用 | 礼品卡业务场景 | 代码示例 | |
|---|---|---|---|---|
| getName(String path) | 提取文件名(兼容所有系统路径) | 获取上传图片的文件名 | String fileName = FilenameUtils.getName("D:/upload/cover.png"); // 结果:cover.png | |
| getExtension(String path) | 提取文件后缀 | 校验上传文件格式(仅允许 png/jpg) | `String ext = FilenameUtils.getExtension(filePath); Validate.isTrue("png".equals(ext) | "jpg".equals (ext), "仅支持 png/jpg 格式");` |
| concat(String basePath, String fileName) | 拼接路径(自动适配系统分隔符) | 拼接图片存储路径 | String fullPath = FilenameUtils.concat("static/images", fileName); | |
| normalize(String path) | 标准化路径(处理../ 等符号) | 修复用户上传的不规则路径 | String normalPath = FilenameUtils.normalize("static/../images/cover.png"); // 结果:images/cover.png |
三、避坑指南(新手必看)
1. 版本冲突坑
- 问题:引入
commons-lang(注意没有 3)和commons-lang3会冲突,commons-lang是旧版本(已停止维护)。 - 解决:只引入
commons-lang3,避免同时引入两个版本。
2. 线程安全坑
- 问题:用
SimpleDateFormat格式化日期,多线程环境下会出现日期错乱。 - 解决:用
commons-lang3的FastDateFormat,全局定义为静态变量复用(如上文示例)。
3. 判空方法选择坑
- 问题:混淆
isEmpty()和isBlank(),导致纯空格参数校验失败。 - 解决:业务中优先用
StringUtils.isBlank()(识别 null / 空串 / 纯空格),isEmpty()仅识别 null / 空串,几乎不用。
| 方法 | null | ""(空串) | " "(纯空格) | 适用场景 |
|---|---|---|---|---|
| isEmpty() | true | true | false | 极少场景(需精确判断空串) |
| isBlank() | true | true | true | 绝大多数业务判空 |
4. 异常处理坑
- 问题:
FileUtils和IOUtils的方法会抛IOException,直接忽略会导致编译报错。 - 解决:两种方式:
- 用
try-catch捕获异常,打印日志:try {FileUtils.writeStringToFile(report, content, "UTF-8"); } catch (IOException e) {log.error("生成报告失败", e); // 用日志框架打印异常throw new RuntimeException("生成报告失败"); } - 在方法上声明
throws IOException(适合工具类方法)。
- 用
5. 路径兼容坑
- 问题:Windows 系统用
\作为路径分隔符,Linux 用/,直接写死路径会导致跨系统部署失败。 - 解决:用
FilenameUtils.concat()拼接路径,自动适配系统分隔符,不要手动写\或/。
四、实战示例(直接复制到项目用)
以下是结合礼品卡系统的完整示例,包含参数校验、日期处理、报告生成:
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.lang3.time.FastDateFormat;
import org.apache.commons.io.FileUtils;import java.io.File;
import java.math.BigDecimal;
import java.util.Date;public class GiftCardCommonsDemo {private static final FastDateFormat DATETIME_FORMATTER = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss");// 礼品卡参数校验+创建public static void createGiftCard(String giftCardNo, BigDecimal amount, String expireDateStr) throws Exception {// 1. 参数校验(StringUtils+Validate)Validate.notBlank(giftCardNo, "卡号不能为空");Validate.isTrue(StringUtils.length(giftCardNo) == 11, "卡号必须为11位");Validate.notNull(amount, "金额不能为空");Validate.isTrue(amount.compareTo(BigDecimal.ZERO) > 0, "金额必须大于0");Validate.notBlank(expireDateStr, "有效期不能为空");// 2. 日期处理(DateUtils)Date expireDate = DateUtils.parseDate(expireDateStr, "yyyy-MM-dd");Validate.isTrue(!DateUtils.isBeforeNow(expireDate), "有效期不能早于当前时间");String createTime = DATETIME_FORMATTER.format(new Date());// 3. 生成创建日志(FileUtils)String logContent = String.format("礼品卡创建成功:卡号=%s,金额=%.2f元,有效期=%s,创建时间=%s",giftCardNo, amount, expireDateStr, createTime);File logFile = new File("gift_card_create_log.txt");FileUtils.writeStringToFile(logFile, logContent + "\n", "UTF-8", true); // 追加写入System.out.println(logContent);}public static void main(String[] args) throws Exception {// 测试创建礼品卡createGiftCard("GC202405201", new BigDecimal("100"), "2024-12-31");}
}
运行后会生成日志文件,输出结果:礼品卡创建成功:卡号=GC202405201,金额=100.00元,有效期=2024-12-31,创建时间=2024-05-20 16:30:00
五、总结
Apache Commons 工具包是 Java 后端的 “必备工具”,commons-lang3和commons-io更是覆盖了大部分高频场景。本文整理的速查表和实战示例,新手可以直接复制使用,老手可以快速查阅,建议收藏备用~
如果在使用过程中遇到问题,或者有其他好用的方法,欢迎在评论区交流补充!
- commons-lang3 官方文档:https://commons.apache.org/proper/commons-lang/
- commons-io 官方文档:https://commons.apache.org/proper/commons-io/
