前言:为什么需要Apache Commons?
如果你写Java时经常遇到这些场景:
- 判断字符串是否为空,写了一堆
str != null && !str.isEmpty() - 复制对象属性,写了几十行getter/setter
- 读取文件内容,try-catch-finally嵌套三层
- 集合操作,各种for循环写到手软
那么恭喜你,Apache Commons就是来拯救你的!
一、Apache Commons 全家福
Apache Commons是Apache软件基金会的一个项目,提供了大量可复用的Java组件。它就像一个工具箱,里面装满了各种实用工具。
flowchart TB
subgraph ApacheCommons[Apache Commons 全家福]
subgraph 核心工具[核心工具类]
Lang[Commons Lang
字符串/对象/反射] Collections[Commons Collections
集合增强] IO[Commons IO
IO操作] end subgraph 数据处理[数据处理] BeanUtils[Commons BeanUtils
Bean操作] Codec[Commons Codec
编解码] CSV[Commons CSV
CSV处理] Compress[Commons Compress
压缩解压] end subgraph 网络相关[网络相关] HttpClient[HttpClient
HTTP客户端] Net[Commons Net
网络协议] Email[Commons Email
邮件发送] end subgraph 其他工具[其他工具] Pool[Commons Pool
对象池] DBCP[Commons DBCP
数据库连接池] CLI[Commons CLI
命令行解析] Config[Commons Configuration
配置管理] end end
字符串/对象/反射] Collections[Commons Collections
集合增强] IO[Commons IO
IO操作] end subgraph 数据处理[数据处理] BeanUtils[Commons BeanUtils
Bean操作] Codec[Commons Codec
编解码] CSV[Commons CSV
CSV处理] Compress[Commons Compress
压缩解压] end subgraph 网络相关[网络相关] HttpClient[HttpClient
HTTP客户端] Net[Commons Net
网络协议] Email[Commons Email
邮件发送] end subgraph 其他工具[其他工具] Pool[Commons Pool
对象池] DBCP[Commons DBCP
数据库连接池] CLI[Commons CLI
命令行解析] Config[Commons Configuration
配置管理] end end
1.1 版本选择指南
| 组件 | 最新稳定版 | JDK要求 | Maven坐标 |
|---|---|---|---|
| commons-lang3 | 3.14.0 | JDK 8+ | org.apache.commons:commons-lang3 |
| commons-collections4 | 4.4 | JDK 8+ | org.apache.commons:commons-collections4 |
| commons-io | 2.15.1 | JDK 8+ | commons-io:commons-io |
| commons-codec | 1.16.0 | JDK 8+ | commons-codec:commons-codec |
| commons-beanutils | 1.9.4 | JDK 8+ | commons-beanutils:commons-beanutils |
| httpclient5 | 5.3 | JDK 8+ | org.apache.httpcomponents.client5:httpclient5 |
注意:commons-lang 和 commons-lang3 是两个不同的包!commons-lang3 是新版本,包名以 org.apache.commons.lang3 开头。
二、Commons Lang3:字符串和对象操作神器
这是使用频率最高的Commons组件,没有之一。
2.1 Maven依赖
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.14.0</version>
</dependency>2.2 StringUtils:告别空指针
flowchart LR
subgraph StringUtils常用方法
A[判空系列] --> A1[isEmpty]
A --> A2[isBlank]
A --> A3[isNotEmpty]
A --> A4[isNotBlank]
B[处理系列] --> B1[trim]
B --> B2[strip]
B --> B3[truncate]
B --> B4[abbreviate]
C[判断系列] --> C1[equals]
C --> C2[contains]
C --> C3[startsWith]
C --> C4[endsWith]
D[转换系列] --> D1[join]
D --> D2[split]
D --> D3[replace]
D --> D4[reverse]
end
判空方法对比(划重点!)
import org.apache.commons.lang3.StringUtils;
// isEmpty vs isBlank 的区别
StringUtils.isEmpty(null); // true
StringUtils.isEmpty(""); // true
StringUtils.isEmpty(" "); // false ← 注意!空格不算空
StringUtils.isEmpty("abc"); // false
StringUtils.isBlank(null); // true
StringUtils.isBlank(""); // true
StringUtils.isBlank(" "); // true ← 空格也算空
StringUtils.isBlank("abc"); // false
// 实际开发中,90%的情况应该用 isBlank
if (StringUtils.isBlank(username)) {
throw new IllegalArgumentException("用户名不能为空");
}常用字符串操作
// 1. 安全的equals(再也不用担心NPE了)
StringUtils.equals(null, null); // true
StringUtils.equals(null, "abc"); // false
StringUtils.equals("abc", "abc"); // true
// 忽略大小写比较
StringUtils.equalsIgnoreCase("ABC", "abc"); // true
// 2. 字符串截取(安全,不会越界)
StringUtils.substring("abcdef", 2); // "cdef"
StringUtils.substring("abcdef", 2, 4); // "cd"
StringUtils.substring("abcdef", -2); // "ef" 负数从后往前
StringUtils.substring(null, 2); // null 不会NPE
// 3. 左右填充(格式化输出神器)
StringUtils.leftPad("123", 5, '0'); // "00123"
StringUtils.rightPad("abc", 5, '*'); // "abc**"
StringUtils.center("abc", 7, '*'); // "**abc**"
// 4. 移除/替换
StringUtils.remove("abcabc", "a"); // "bcbc"
StringUtils.removeStart("www.baidu.com", "www."); // "baidu.com"
StringUtils.removeEnd("hello.txt", ".txt"); // "hello"
// 5. 分割与连接
String[] arr = StringUtils.split("a,b,c", ","); // ["a", "b", "c"]
StringUtils.join(arr, "-"); // "a-b-c"
// 处理null元素
String[] arr2 = {"a", null, "c"};
StringUtils.join(arr2, ","); // "a,,c"
// 6. 省略过长字符串
StringUtils.abbreviate("这是一段很长很长的文字", 10); // "这是一段很长很..."
StringUtils.abbreviateMiddle("abcdefghij", "...", 6); // "ab...j"2.3 ObjectUtils:对象操作
import org.apache.commons.lang3.ObjectUtils;
// 1. 空值处理
ObjectUtils.defaultIfNull(null, "默认值"); // "默认值"
ObjectUtils.defaultIfNull("有值", "默认值"); // "有值"
// 2. 第一个非空值(类似SQL的COALESCE)
ObjectUtils.firstNonNull(null, null, "第三个", "第四个"); // "第三个"
// 3. 比较(null安全)
ObjectUtils.compare(1, 2); // -1
ObjectUtils.compare(null, 2); // -1 (null视为最小)
ObjectUtils.compare(null, null); // 0
// 4. 判空
ObjectUtils.isEmpty(null); // true
ObjectUtils.isEmpty(""); // true
ObjectUtils.isEmpty(new int[0]); // true
ObjectUtils.isEmpty(Collections.emptyList()); // true2.4 NumberUtils:数字处理
import org.apache.commons.lang3.math.NumberUtils;
// 1. 安全的字符串转数字(不会抛异常)
NumberUtils.toInt("123"); // 123
NumberUtils.toInt("abc"); // 0 (转换失败返回0)
NumberUtils.toInt("abc", -1); // -1 (转换失败返回默认值)
NumberUtils.toLong("9999999999"); // 9999999999L
NumberUtils.toDouble("3.14"); // 3.14
// 2. 判断字符串是否为数字
NumberUtils.isDigits("123"); // true (纯数字)
NumberUtils.isDigits("12.3"); // false
NumberUtils.isParsable("12.3"); // true (可解析为数字)
NumberUtils.isParsable("12.3.4"); // false
NumberUtils.isCreatable("0x10"); // true (支持十六进制)
// 3. 取最大/最小值
NumberUtils.max(1, 5, 3, 2, 4); // 5
NumberUtils.min(1, 5, 3, 2, 4); // 12.5 ArrayUtils:数组操作
import org.apache.commons.lang3.ArrayUtils;
// 1. 数组判空
ArrayUtils.isEmpty(null); // true
ArrayUtils.isEmpty(new int[0]); // true
ArrayUtils.isEmpty(new int[]{1}); // false
// 2. 数组添加元素
int[] arr = {1, 2, 3};
int[] newArr = ArrayUtils.add(arr, 4); // [1, 2, 3, 4]
int[] newArr2 = ArrayUtils.insert(1, arr, 9); // [1, 9, 2, 3]
// 3. 数组删除元素
ArrayUtils.remove(arr, 1); // [1, 3] 删除索引1的元素
ArrayUtils.removeElement(arr, 2); // [1, 3] 删除值为2的元素
// 4. 查找
ArrayUtils.contains(arr, 2); // true
ArrayUtils.indexOf(arr, 2); // 1
// 5. 反转和打乱
ArrayUtils.reverse(arr); // [3, 2, 1]
ArrayUtils.shuffle(arr); // 随机打乱
// 6. 基本类型与包装类型转换
int[] primitiveArr = {1, 2, 3};
Integer[] boxedArr = ArrayUtils.toObject(primitiveArr);
int[] backToPrimitive = ArrayUtils.toPrimitive(boxedArr);
// 7. 数组转字符串
ArrayUtils.toString(new int[]{1, 2, 3}); // "{1,2,3}"2.6 DateUtils(已过时,推荐用Java 8 Time API)
import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
// 1. 日期解析(支持多种格式)
Date date = DateUtils.parseDate("2024-01-15",
"yyyy-MM-dd", "yyyy/MM/dd", "yyyyMMdd");
// 2. 日期计算
Date tomorrow = DateUtils.addDays(new Date(), 1);
Date nextMonth = DateUtils.addMonths(new Date(), 1);
Date nextYear = DateUtils.addYears(new Date(), 1);
// 3. 日期截断
Date truncated = DateUtils.truncate(new Date(), Calendar.DAY_OF_MONTH);
// 4. 日期格式化
String formatted = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");2.7 RandomStringUtils:随机字符串
import org.apache.commons.lang3.RandomStringUtils;
// 1. 随机字母
RandomStringUtils.randomAlphabetic(10); // "KjHgFdSaQw"
// 2. 随机数字
RandomStringUtils.randomNumeric(6); // "482951"
// 3. 随机字母+数字
RandomStringUtils.randomAlphanumeric(8); // "Kj8Hg2Fd"
// 4. 从指定字符中随机
RandomStringUtils.random(4, "ABCD1234"); // "B3A1"
// 5. 随机ASCII
RandomStringUtils.randomAscii(10); // 包含特殊字符三、Commons Collections4:集合增强
3.1 Maven依赖
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>3.2 CollectionUtils:集合操作
flowchart TB
subgraph CollectionUtils核心功能
A[判空操作] --> A1[isEmpty]
A --> A2[isNotEmpty]
B[集合运算] --> B1[union 并集]
B --> B2[intersection 交集]
B --> B3[subtract 差集]
B --> B4[disjunction 对称差集]
C[查找过滤] --> C1[find]
C --> C2[filter]
C --> C3[select]
C --> C4[exists]
D[转换操作] --> D1[transform]
D --> D2[collect]
end
import org.apache.commons.collections4.CollectionUtils;
List<Integer> list1 = Arrays.asList(1, 2, 3, 4);
List<Integer> list2 = Arrays.asList(3, 4, 5, 6);
// 1. 判空
CollectionUtils.isEmpty(null); // true
CollectionUtils.isEmpty(new ArrayList<>()); // true
CollectionUtils.isNotEmpty(list1); // true
// 2. 集合运算
Collection<Integer> union = CollectionUtils.union(list1, list2);
// [1, 2, 3, 4, 5, 6] 并集
Collection<Integer> intersection = CollectionUtils.intersection(list1, list2);
// [3, 4] 交集
Collection<Integer> subtract = CollectionUtils.subtract(list1, list2);
// [1, 2] 差集(list1有而list2没有的)
Collection<Integer> disjunction = CollectionUtils.disjunction(list1, list2);
// [1, 2, 5, 6] 对称差集(两边独有的)
// 3. 安全添加
CollectionUtils.addIgnoreNull(list1, null); // 忽略null元素
// 4. 判断是否相等(忽略顺序)
CollectionUtils.isEqualCollection(
Arrays.asList(1, 2, 3),
Arrays.asList(3, 2, 1)
); // trueflowchart LR
subgraph 集合运算图解
subgraph List1[List1: 1,2,3,4]
L1_1[1]
L1_2[2]
L1_3[3]
L1_4[4]
end
subgraph List2[List2: 3,4,5,6]
L2_3[3]
L2_4[4]
L2_5[5]
L2_6[6]
end
subgraph Results[运算结果]
R1[并集: 1,2,3,4,5,6]
R2[交集: 3,4]
R3[差集: 1,2]
R4[对称差: 1,2,5,6]
end
end
3.3 MapUtils:Map操作
import org.apache.commons.collections4.MapUtils;
Map<String, Object> map = new HashMap<>();
map.put("name", "Joey");
map.put("age", "25");
map.put("score", "98.5");
map.put("active", "true");
// 1. 安全取值(带类型转换)
MapUtils.getString(map, "name"); // "Joey"
MapUtils.getString(map, "notExist", "默认"); // "默认"
MapUtils.getInteger(map, "age"); // 25 (自动转换)
MapUtils.getIntValue(map, "age"); // 25 (返回基本类型)
MapUtils.getIntValue(map, "notExist", 0); // 0
MapUtils.getDouble(map, "score"); // 98.5
MapUtils.getBoolean(map, "active"); // true
// 2. 判空
MapUtils.isEmpty(null); // true
MapUtils.isEmpty(new HashMap<>()); // true
MapUtils.isNotEmpty(map); // true
// 3. 反转Map(key-value互换)
Map<String, String> original = new HashMap<>();
original.put("a", "1");
original.put("b", "2");
Map<String, String> inverted = MapUtils.invertMap(original);
// {"1": "a", "2": "b"}
// 4. 打印Map(调试用)
MapUtils.debugPrint(System.out, "myMap", map);3.4 特殊集合类型
import org.apache.commons.collections4.bag.HashBag;
import org.apache.commons.collections4.bidimap.TreeBidiMap;
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
// 1. Bag - 可统计元素出现次数的集合
Bag<String> bag = new HashBag<>();
bag.add("apple", 3); // 添加3个apple
bag.add("banana");
bag.add("apple"); // 再添加1个apple
bag.getCount("apple"); // 4
// 2. BidiMap - 双向Map(可以通过value找key)
BidiMap<String, Integer> bidiMap = new TreeBidiMap<>();
bidiMap.put("one", 1);
bidiMap.put("two", 2);
bidiMap.get("one"); // 1
bidiMap.getKey(1); // "one"
bidiMap.inverseBidiMap(); // 获取反转的Map
// 3. MultiValuedMap - 一个key对应多个value
MultiValuedMap<String, String> multiMap = new ArrayListValuedHashMap<>();
multiMap.put("color", "red");
multiMap.put("color", "blue");
multiMap.put("color", "green");
multiMap.get("color"); // [red, blue, green]四、Commons IO:文件操作神器
4.1 Maven依赖
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.15.1</version>
</dependency>4.2 FileUtils:文件操作
flowchart TB
subgraph FileUtils功能
A[读写操作] --> A1[readFileToString]
A --> A2[writeStringToFile]
A --> A3[readLines]
A --> A4[writeLines]
B[复制操作] --> B1[copyFile]
B --> B2[copyDirectory]
B --> B3[copyURLToFile]
C[删除操作] --> C1[deleteQuietly]
C --> C2[deleteDirectory]
C --> C3[cleanDirectory]
D[其他操作] --> D1[listFiles]
D --> D2[sizeOf]
D --> D3[moveFile]
D --> D4[touch]
end
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.nio.charset.StandardCharsets;
// 1. 读取文件
// 一行代码读取文件内容,告别繁琐的流操作
String content = FileUtils.readFileToString(
new File("test.txt"),
StandardCharsets.UTF_8
);
// 按行读取
List<String> lines = FileUtils.readLines(
new File("test.txt"),
StandardCharsets.UTF_8
);
// 2. 写入文件
FileUtils.writeStringToFile(
new File("output.txt"),
"Hello World",
StandardCharsets.UTF_8
);
// 追加写入
FileUtils.writeStringToFile(
new File("output.txt"),
"\nNew Line",
StandardCharsets.UTF_8,
true // append
);
// 写入多行
FileUtils.writeLines(
new File("output.txt"),
Arrays.asList("line1", "line2", "line3")
);
// 3. 复制文件/目录
FileUtils.copyFile(
new File("source.txt"),
new File("dest.txt")
);
FileUtils.copyDirectory(
new File("sourceDir"),
new File("destDir")
);
// 从URL下载文件
FileUtils.copyURLToFile(
new URL("https://example.com/file.zip"),
new File("downloaded.zip"),
5000, // 连接超时
10000 // 读取超时
);
// 4. 删除文件/目录
FileUtils.deleteQuietly(new File("test.txt")); // 静默删除,不抛异常
FileUtils.deleteDirectory(new File("testDir")); // 删除目录及其内容
FileUtils.cleanDirectory(new File("testDir")); // 清空目录但保留目录本身
// 5. 文件/目录大小
long fileSize = FileUtils.sizeOf(new File("large.zip"));
long dirSize = FileUtils.sizeOfDirectory(new File("myDir"));
String readable = FileUtils.byteCountToDisplaySize(fileSize); // "1.5 GB"
// 6. 列出文件
Collection<File> files = FileUtils.listFiles(
new File("myDir"),
new String[]{"java", "xml"}, // 扩展名过滤
true // 递归子目录
);
// 7. 比较文件
boolean same = FileUtils.contentEquals(
new File("file1.txt"),
new File("file2.txt")
);
// 8. 移动文件
FileUtils.moveFile(
new File("source.txt"),
new File("newDir/dest.txt")
);
// 9. 创建文件/更新时间戳
FileUtils.touch(new File("newFile.txt"));4.3 IOUtils:流操作
import org.apache.commons.io.IOUtils;
// 1. 流转字符串
try (InputStream is = new FileInputStream("test.txt")) {
String content = IOUtils.toString(is, StandardCharsets.UTF_8);
}
// 2. 流转字节数组
try (InputStream is = new FileInputStream("image.png")) {
byte[] bytes = IOUtils.toByteArray(is);
}
// 3. 流复制
try (InputStream is = new FileInputStream("source.txt");
OutputStream os = new FileOutputStream("dest.txt")) {
IOUtils.copy(is, os);
}
// 4. 逐行读取
try (InputStream is = new FileInputStream("test.txt")) {
List<String> lines = IOUtils.readLines(is, StandardCharsets.UTF_8);
}
// 5. 写入流
try (OutputStream os = new FileOutputStream("test.txt")) {
IOUtils.write("Hello World", os, StandardCharsets.UTF_8);
}
// 6. 安全关闭流(不推荐,用try-with-resources更好)
IOUtils.closeQuietly(inputStream);4.4 FilenameUtils:文件名处理
import org.apache.commons.io.FilenameUtils;
String path = "/home/user/documents/report.pdf";
// 1. 获取文件名
FilenameUtils.getName(path); // "report.pdf"
FilenameUtils.getBaseName(path); // "report"
FilenameUtils.getExtension(path); // "pdf"
// 2. 获取路径
FilenameUtils.getFullPath(path); // "/home/user/documents/"
FilenameUtils.getPath(path); // "home/user/documents/"
// 3. 路径拼接(自动处理分隔符)
FilenameUtils.concat("/home/user", "file.txt"); // "/home/user/file.txt"
// 4. 标准化路径(处理..和.)
FilenameUtils.normalize("/home/user/../admin/./file.txt");
// "/home/admin/file.txt"
// 5. 检查扩展名
FilenameUtils.isExtension("test.txt", "txt"); // true
FilenameUtils.isExtension("test.txt", new String[]{"txt", "doc"}); // true
// 6. 通配符匹配
FilenameUtils.wildcardMatch("test.txt", "*.txt"); // true
FilenameUtils.wildcardMatch("test.txt", "test.*"); // true
FilenameUtils.wildcardMatch("test.txt", "t?st.txt"); // true五、Commons BeanUtils:Bean操作
5.1 Maven依赖
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.4</version>
</dependency>5.2 属性复制
sequenceDiagram
participant Source as 源对象
participant BeanUtils as BeanUtils
participant Target as 目标对象
Source->>BeanUtils: copyProperties(dest, src)
BeanUtils->>BeanUtils: 反射获取源对象属性
BeanUtils->>BeanUtils: 类型转换
BeanUtils->>Target: 设置属性值
Note over Target: 属性复制完成
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
// 假设有两个类
public class UserDTO {
private String name;
private String age; // 注意是String
// getters and setters
}
public class UserEntity {
private String name;
private Integer age; // 注意是Integer
// getters and setters
}
// 1. 属性复制(会进行类型转换)
UserDTO dto = new UserDTO();
dto.setName("Joey");
dto.setAge("25");
UserEntity entity = new UserEntity();
BeanUtils.copyProperties(entity, dto); // 注意:目标在前,源在后!
// entity.name = "Joey", entity.age = 25
// 2. 获取/设置属性
BeanUtils.getProperty(dto, "name"); // "Joey"
BeanUtils.setProperty(dto, "name", "Tom");
// 3. 嵌套属性
public class Order {
private User user;
}
BeanUtils.getProperty(order, "user.name"); // 获取嵌套属性
// 4. PropertyUtils(不做类型转换)
PropertyUtils.copyProperties(entity, dto); // 类型不匹配会报错
PropertyUtils.getProperty(dto, "name");
// 5. Map与Bean互转
Map<String, String> map = BeanUtils.describe(dto); // Bean转Map
BeanUtils.populate(dto, map); // Map转Bean⚠️ 性能警告:BeanUtils基于反射,性能较差。高性能场景推荐使用:
- MapStruct(编译期生成代码)
- Spring BeanUtils(相对更快)
- 手写getter/setter
六、Commons Codec:编解码工具
6.1 Maven依赖
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.16.0</version>
</dependency>6.2 常用编解码
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.codec.net.URLCodec;
// 1. Base64编解码
String encoded = Base64.encodeBase64String("Hello World".getBytes());
// "SGVsbG8gV29ybGQ="
byte[] decoded = Base64.decodeBase64(encoded);
// "Hello World"
// URL安全的Base64
String urlSafe = Base64.encodeBase64URLSafeString("Hello World".getBytes());
// 2. Hex编解码
String hex = Hex.encodeHexString("Hello".getBytes()); // "48656c6c6f"
byte[] fromHex = Hex.decodeHex(hex);
// 3. MD5/SHA摘要
String md5 = DigestUtils.md5Hex("password");
String sha1 = DigestUtils.sha1Hex("password");
String sha256 = DigestUtils.sha256Hex("password");
String sha512 = DigestUtils.sha512Hex("password");
// 文件MD5
String fileMd5 = DigestUtils.md5Hex(new FileInputStream("file.txt"));
// 4. URL编解码
URLCodec urlCodec = new URLCodec();
String urlEncoded = urlCodec.encode("中文参数"); // "%E4%B8%AD%E6%96%87..."
String urlDecoded = urlCodec.decode(urlEncoded);flowchart LR
subgraph 编码类型选择
A[原始数据] --> B{用途?}
B -->|网络传输| C[Base64]
B -->|URL参数| D[URLEncode]
B -->|密码存储| E[SHA256 + Salt]
B -->|文件校验| F[MD5/SHA1]
B -->|调试查看| G[Hex]
end
七、其他常用组件
7.1 Commons CSV:CSV文件处理
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>
<version>1.10.0</version>
</dependency>import org.apache.commons.csv.*;
// 1. 读取CSV
try (Reader reader = new FileReader("data.csv");
CSVParser parser = CSVFormat.DEFAULT
.withFirstRecordAsHeader()
.parse(reader)) {
for (CSVRecord record : parser) {
String name = record.get("name");
String age = record.get("age");
}
}
// 2. 写入CSV
try (Writer writer = new FileWriter("output.csv");
CSVPrinter printer = new CSVPrinter(writer, CSVFormat.DEFAULT
.withHeader("name", "age", "email"))) {
printer.printRecord("Joey", 25, "joey@example.com");
printer.printRecord("Tom", 30, "tom@example.com");
}7.2 Commons Compress:压缩解压
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.25.0</version>
</dependency>import org.apache.commons.compress.archivers.zip.*;
import org.apache.commons.compress.utils.IOUtils;
// 1. 创建ZIP文件
try (ZipArchiveOutputStream zos = new ZipArchiveOutputStream(
new FileOutputStream("archive.zip"))) {
File fileToZip = new File("document.txt");
ZipArchiveEntry entry = new ZipArchiveEntry(fileToZip, fileToZip.getName());
zos.putArchiveEntry(entry);
IOUtils.copy(new FileInputStream(fileToZip), zos);
zos.closeArchiveEntry();
}
// 2. 解压ZIP文件
try (ZipFile zipFile = new ZipFile("archive.zip")) {
Enumeration<ZipArchiveEntry> entries = zipFile.getEntries();
while (entries.hasMoreElements()) {
ZipArchiveEntry entry = entries.nextElement();
File destFile = new File("output", entry.getName());
try (InputStream is = zipFile.getInputStream(entry);
OutputStream os = new FileOutputStream(destFile)) {
IOUtils.copy(is, os);
}
}
}7.3 Commons Pool2:对象池
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.12.0</version>
</dependency>sequenceDiagram
participant Client as 客户端
participant Pool as 对象池
participant Factory as 对象工厂
Client->>Pool: borrowObject()
alt 池中有空闲对象
Pool->>Client: 返回空闲对象
else 池中无空闲对象
Pool->>Factory: makeObject()
Factory->>Pool: 新对象
Pool->>Client: 返回新对象
end
Client->>Client: 使用对象
Client->>Pool: returnObject()
Pool->>Pool: 对象回归池中
import org.apache.commons.pool2.*;
import org.apache.commons.pool2.impl.*;
// 1. 定义对象工厂
public class MyConnectionFactory extends BasePooledObjectFactory<MyConnection> {
@Override
public MyConnection create() {
return new MyConnection(); // 创建新对象
}
@Override
public PooledObject<MyConnection> wrap(MyConnection conn) {
return new DefaultPooledObject<>(conn);
}
@Override
public void destroyObject(PooledObject<MyConnection> p) {
p.getObject().close(); // 销毁对象
}
@Override
public boolean validateObject(PooledObject<MyConnection> p) {
return p.getObject().isValid(); // 验证对象是否有效
}
}
// 2. 创建对象池
GenericObjectPoolConfig<MyConnection> config = new GenericObjectPoolConfig<>();
config.setMaxTotal(10); // 最大对象数
config.setMaxIdle(5); // 最大空闲数
config.setMinIdle(2); // 最小空闲数
config.setTestOnBorrow(true); // 借出时验证
GenericObjectPool<MyConnection> pool = new GenericObjectPool<>(
new MyConnectionFactory(), config
);
// 3. 使用对象池
MyConnection conn = null;
try {
conn = pool.borrowObject(); // 借出对象
conn.doSomething();
} finally {
if (conn != null) {
pool.returnObject(conn); // 归还对象
}
}7.4 Commons CLI:命令行解析
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.6.0</version>
</dependency>import org.apache.commons.cli.*;
// 定义选项
Options options = new Options();
options.addOption("h", "help", false, "显示帮助信息");
options.addOption("v", "version", false, "显示版本");
options.addOption("f", "file", true, "输入文件路径");
options.addOption("o", "output", true, "输出文件路径");
// 解析命令行
CommandLineParser parser = new DefaultParser();
try {
CommandLine cmd = parser.parse(options, args);
if (cmd.hasOption("h")) {
HelpFormatter formatter = new HelpFormatter();
formatter.printHelp("myapp", options);
return;
}
if (cmd.hasOption("f")) {
String inputFile = cmd.getOptionValue("f");
System.out.println("Input file: " + inputFile);
}
} catch (ParseException e) {
System.err.println("解析错误: " + e.getMessage());
}
// 使用示例: java -jar myapp.jar -f input.txt -o output.txt八、最佳实践与踩坑指南
8.1 版本选择
flowchart TB
A[选择Apache Commons版本] --> B{项目JDK版本?}
B -->|JDK 8+| C[使用最新稳定版]
B -->|JDK 7| D[查看兼容版本]
B -->|JDK 6| E[考虑升级JDK]
C --> F{是否有历史依赖?}
F -->|有commons-lang| G[迁移到commons-lang3]
F -->|有commons-collections| H[迁移到commons-collections4]
F -->|无| I[直接使用新版]
8.2 常见踩坑
坑1:BeanUtils.copyProperties参数顺序
// ❌ 错误!很多人会搞反
BeanUtils.copyProperties(source, dest);
// ✅ 正确!dest在前,source在后
BeanUtils.copyProperties(dest, source);
// 💡 记忆技巧:想象成 dest = source坑2:StringUtils.isEmpty vs isBlank
String str = " ";
// ❌ 可能不是你想要的
if (StringUtils.isEmpty(str)) { // false!
// 不会进入
}
// ✅ 通常你想要的是这个
if (StringUtils.isBlank(str)) { // true
// 会进入
}坑3:commons-lang vs commons-lang3
// ❌ 旧版本(已过时)
import org.apache.commons.lang.StringUtils;
// ✅ 新版本
import org.apache.commons.lang3.StringUtils;
// 两个包不能混用!坑4:BeanUtils性能问题
// ❌ 在循环中使用BeanUtils(性能差)
for (UserDTO dto : dtoList) {
UserEntity entity = new UserEntity();
BeanUtils.copyProperties(entity, dto); // 每次都反射
entities.add(entity);
}
// ✅ 使用MapStruct或手写转换
for (UserDTO dto : dtoList) {
entities.add(userMapper.toEntity(dto)); // 编译期生成代码
}坑5:FileUtils.deleteDirectory的陷阱
// ❌ 危险!如果路径错误可能删除重要文件
FileUtils.deleteDirectory(new File(userInputPath));
// ✅ 先验证路径
File dir = new File(userInputPath);
if (dir.exists() && dir.isDirectory()
&& dir.getAbsolutePath().startsWith("/safe/path/")) {
FileUtils.deleteDirectory(dir);
}8.3 性能对比参考
| 操作 | Apache Commons | 替代方案 | 性能比较 | ||
|---|---|---|---|---|---|
| 字符串判空 | StringUtils.isBlank | str == null \ | \ | str.trim().isEmpty() | 相当 |
| 属性复制 | BeanUtils | MapStruct | MapStruct快10-100倍 | ||
| 集合操作 | CollectionUtils | Stream API | Stream更灵活 | ||
| 文件读取 | FileUtils | Files.readString (JDK11+) | 相当 | ||
| JSON处理 | 无 | Jackson/Gson | 使用Jackson |
8.4 与现代Java的关系
flowchart LR
subgraph Java8之前[Java 8 之前]
A1[Commons Lang] --> B1[字符串/对象操作]
A2[Commons Collections] --> B2[集合操作]
A3[Commons IO] --> B3[文件IO]
end
subgraph Java8之后[Java 8+ 可替代部分]
C1[Optional] --> D1[空值处理]
C2[Stream API] --> D2[集合操作]
C3[java.time] --> D3[日期处理]
C4[Files类] --> D4[文件IO]
end
subgraph 仍然有用[仍然推荐使用]
E1[StringUtils] --> F1[字符串判空等]
E2[FileUtils] --> F2[复杂文件操作]
E3[DigestUtils] --> F3[摘要计算]
E4[特殊集合] --> F4[Bag/BidiMap等]
end
九、快速参考卡片
StringUtils速查
// 判空
StringUtils.isBlank(str) // null/""/空格 都返回true
StringUtils.isEmpty(str) // null/"" 返回true
// 默认值
StringUtils.defaultString(str) // null → ""
StringUtils.defaultString(str, "default") // null → "default"
StringUtils.defaultIfBlank(str, "default")
// 截取
StringUtils.left(str, 5) // 左边5个字符
StringUtils.right(str, 5) // 右边5个字符
StringUtils.mid(str, 2, 5) // 从位置2开始取5个
StringUtils.substringBefore(str, ",")
StringUtils.substringAfter(str, ",")
// 判断
StringUtils.contains(str, "abc")
StringUtils.containsIgnoreCase(str, "ABC")
StringUtils.startsWith(str, "prefix")
StringUtils.endsWith(str, "suffix")CollectionUtils速查
// 判空
CollectionUtils.isEmpty(collection)
CollectionUtils.isNotEmpty(collection)
// 集合运算
CollectionUtils.union(a, b) // 并集
CollectionUtils.intersection(a, b) // 交集
CollectionUtils.subtract(a, b) // 差集
// 安全操作
CollectionUtils.emptyIfNull(collection)
CollectionUtils.size(collection) // null安全FileUtils速查
// 读
FileUtils.readFileToString(file, charset)
FileUtils.readLines(file, charset)
// 写
FileUtils.writeStringToFile(file, data, charset)
FileUtils.writeLines(file, lines)
// 复制
FileUtils.copyFile(src, dest)
FileUtils.copyDirectory(srcDir, destDir)
// 删除
FileUtils.deleteQuietly(file)
FileUtils.deleteDirectory(dir)
FileUtils.cleanDirectory(dir)总结
Apache Commons是Java开发的得力助手,但也要注意:
- 不要过度依赖:Java 8+已经提供了很多替代方案
- 注意版本:使用
lang3和collections4等新版本 - 性能敏感场景:BeanUtils等基于反射的工具要谨慎使用
- 保持更新:定期升级依赖,获取bug修复和性能优化
最后的最后:工具再好,也要知道它的边界。了解原理,才能用得更好!🚀