Java Apache Commons
Apache Commons 是 Apache 软件基金会提供的一系列 Java 工具库,它们是 Java 生态中最成熟、使用最广泛的基础设施之一。本文介绍几个最常用的 Commons 库。
概述
Apache Commons 项目起源于 Jakarta 项目,目的是提供可复用的 Java 组件。这些库填补了 JDK 标准库的空白,提供了大量实用工具方法。
核心价值:减少样板代码、处理边界情况、提供经过生产验证的实现。
Commons Lang3
最基础也最常用的库,扩展了 java.lang 包的功能。
Maven 依赖
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.17.0</version>
</dependency>字符串工具 - StringUtils
import org.apache.commons.lang3.StringUtils;
// 空值处理 - 避免 NPE
String name = null;
StringUtils.isEmpty(name); // true
StringUtils.isBlank(name); // true (空白也视为空)
StringUtils.defaultIfBlank(name, "default"); // "default"
// 截取与分割
String text = " Hello World ";
StringUtils.trim(text); // "Hello World"
StringUtils.substringBetween(text, "He", "o"); // "ll"
StringUtils.split("a,b,c", ","); // ["a", "b", "c"]
// 拼接
StringUtils.join(["a", "b", "c"], "-"); // "a-b-c"
String[] array = {"Hello", null, "World"};
StringUtils.join(array, " "); // "Hello World" (跳过 null)
// 大小写转换
StringUtils.upperCase("hello"); // "HELLO"
StringUtils.capitalize("hello"); // "Hello"
StringUtils.uncapitalize("Hello"); // "hello"
// 判断
StringUtils.isNumeric("123"); // true
StringUtils.isAlpha("abc"); // true
StringUtils.startsWithIgnoreCase("Hello", "he"); // true对象工具 - ObjectUtils
import org.apache.commons.lang3.ObjectUtils;
// 空值处理
ObjectUtils.firstNonNull(null, null, "value", "other"); // "value"
ObjectUtils.defaultIfNull(null, "default"); // "default"
// 比较
ObjectUtils.compare(1, 2); // -1
ObjectUtils.max(1, 2, 3); // 3
ObjectUtils.min(1, 2, 3); // 1
// 判等(null 安全)
ObjectUtils.notEqual(null, "value"); // true
ObjectUtils.allNull(null, null); // true
ObjectUtils.anyNull(null, "value"); // true数组工具 - ArrayUtils
import org.apache.commons.lang3.ArrayUtils;
int[] nums = {1, 2, 3};
// 添加元素(返回新数组)
ArrayUtils.add(nums, 4); // [1, 2, 3, 4]
ArrayUtils.insert(nums, 1, 99); // [1, 99, 2, 3]
// 删除元素
ArrayUtils.remove(nums, 0); // [2, 3]
ArrayUtils.removeAll(nums, 0, 1); // [3]
// 查找
ArrayUtils.contains(nums, 2); // true
ArrayUtils.indexOf(nums, 2); // 1
// 反转与子数组
ArrayUtils.reverse(nums); // [3, 2, 1]
ArrayUtils.subarray(nums, 0, 2); // [3, 2]
// 空值处理
ArrayUtils.isEmpty(nums); // false
ArrayUtils.nullToEmpty((int[]) null); // []日期工具 - DateUtils
import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.FastDateFormat;
Date now = new Date();
// 日期计算
Date tomorrow = DateUtils.addDays(now, 1);
Date nextMonth = DateUtils.addMonths(now, 1);
Date rounded = DateUtils.round(now, Calendar.HOUR);
// 日期比较
DateUtils.isSameDay(now, tomorrow); // false
DateUtils.truncatedEquals(now, tomorrow, Calendar.DATE); // false
// 格式化(线程安全)
String formatted = DateFormatUtils.format(now, "yyyy-MM-dd HH:mm:ss");
FastDateFormat fdf = FastDateFormat.getInstance("yyyy-MM-dd");随机字符串 - RandomStringUtils
import org.apache.commons.lang3.RandomStringUtils;
// 随机生成
RandomStringUtils.random(10); // 10位随机字符
RandomStringUtils.randomAlphabetic(10); // 10位字母
RandomStringUtils.randomNumeric(10); // 10位数字
RandomStringUtils.randomAlphanumeric(10); // 字母+数字
RandomStringUtils.random(10, "abc123"); // 从指定字符集生成Commons IO
处理文件和 IO 操作的利器。
Maven 依赖
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.18.0</version>
</dependency>IOUtils - 流操作
import org.apache.commons.io.IOUtils;
import java.io.*;
// 流转字符串
String content = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
// 流转字节数组
byte[] bytes = IOUtils.toByteArray(inputStream);
// 复制流
IOUtils.copy(inputStream, outputStream);
IOUtils.copyLarge(inputStream, outputStream); // 大文件
// 关闭流(静默关闭,不抛异常)
IOUtils.closeQuietly(inputStream);
// 比较流内容
boolean same = IOUtils.contentEquals(stream1, stream2);FileUtils - 文件操作
import org.apache.commons.io.FileUtils;
import java.io.File;
File file = new File("test.txt");
File dir = new File("output");
// 读取文件
String content = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
List<String> lines = FileUtils.readLines(file, StandardCharsets.UTF_8);
byte[] bytes = FileUtils.readFileToByteArray(file);
// 写入文件
FileUtils.writeStringToFile(file, "content", StandardCharsets.UTF_8);
FileUtils.writeLines(file, Arrays.asList("line1", "line2"));
FileUtils.writeByteArrayToFile(file, bytes);
// 复制文件
FileUtils.copyFile(srcFile, destFile);
FileUtils.copyDirectory(srcDir, destDir);
FileUtils.copyFileToDirectory(srcFile, destDir);
// 删除
FileUtils.deleteQuietly(file); // 静默删除
FileUtils.forceDelete(dir); // 强制删除
FileUtils.cleanDirectory(dir); // 清空目录内容
// 创建
FileUtils.forceMkdir(dir); // 创建目录
FileUtils.touch(file); // 创建空文件(如不存在)
// 文件信息
long size = FileUtils.sizeOf(file);
long dirSize = FileUtils.sizeOfDirectory(dir);
FileUtils.isFileNewer(file, referenceFile);
FileUtils.isFileOlder(file, referenceFile);
// 遍历文件
Collection<File> files = FileUtils.listFiles(dir, new String[]{"java"}, true);FilenameUtils - 文件名处理
import org.apache.commons.io.FilenameUtils;
String path = "/home/user/docs/readme.txt";
// 获取各部分
FilenameUtils.getExtension(path); // "txt"
FilenameUtils.getBaseName(path); // "readme"
FilenameUtils.getName(path); // "readme.txt"
FilenameUtils.getPath(path); // "/home/user/docs/"
FilenameUtils.getFullPath(path); // "/home/user/docs/"
// 路径规范化
FilenameUtils.normalize("/home/../user"); // "/user"
FilenameUtils.separatorsToUnix("C:\\Users"); // "C:/Users"
// 路径比较
FilenameUtils.equals(path1, path2); // 标准化后比较IOFileFilter - 文件过滤
import org.apache.commons.io.filefilter.*;
// 常用过滤器
FileFilter txtFilter = new SuffixFileFilter(".txt");
FileFilter dirFilter = DirectoryFileFilter.INSTANCE;
FileFilter fileFilter = FileFileFilter.INSTANCE;
// 组合过滤器
IOFileFilter filter = FileFilterUtils.and(
FileFilterUtils.sizeFileFilter(1024 * 1024), // 大于 1MB
new SuffixFileFilter(".log")
);
// 使用过滤器遍历
Collection<File> files = FileUtils.listFiles(dir, filter, null);Commons Collections4
增强 Java 集合框架。
Maven 依赖
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.5.0-M2</version>
</dependency>CollectionUtils
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
List<String> list1 = Arrays.asList("a", "b", "c");
List<String> list2 = Arrays.asList("b", "c", "d");
// 集合操作
Collection<String> union = CollectionUtils.union(list1, list2); // 并集
Collection<String> intersection = CollectionUtils.intersection(list1, list2); // 交集
Collection<String> subtract = CollectionUtils.subtract(list1, list2); // 差集
// 判断
CollectionUtils.isEmpty(list1); // false
CollectionUtils.isNotEmpty(list1); // true
CollectionUtils.containsAny(list1, list2); // true
// 过滤
CollectionUtils.filter(list, e -> e.length() > 1); // 原地过滤
CollectionUtils.select(list, predicate); // 返回新集合
// 转换
CollectionUtils.collect(list, transformer);
// 查找
String found = CollectionUtils.find(list, e -> e.startsWith("a"));
// 分区
List<List<String>> partitions = ListUtils.partition(list1, 2); // 每组2个元素MapUtils
import org.apache.commons.collections4.MapUtils;
Map<String, Object> map = new HashMap<>();
// 安全获取值
MapUtils.getString(map, "key", "default");
MapUtils.getInteger(map, "key", 0);
MapUtils.getBoolean(map, "key", false);
// 判断
MapUtils.isEmpty(map);
MapUtils.isNotEmpty(map);
// 安全 put
MapUtils.safeAddToMap(map, "key", "value");
// 调试输出
MapUtils.verbosePrint(System.out, "Map: ", map);MultiValuedMap - 一键多值
import org.apache.commons.collections4.MultiValuedMap;
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
MultiValuedMap<String, String> map = new ArrayListValuedHashMap<>();
map.put("key", "value1");
map.put("key", "value2");
Collection<String> values = map.get("key"); // [value1, value2]BidiMap - 双向映射
import org.apache.commons.collections4.BidiMap;
import org.apache.commons.collections4.bidimap.TreeBidiMap;
BidiMap<String, Integer> bidiMap = new TreeBidiMap<>();
bidiMap.put("one", 1);
bidiMap.put("two", 2);
String key = bidiMap.getKey(1); // "one"
Integer value = bidiMap.get("one"); // 1
// 反转
BidiMap<Integer, String> inverse = bidiMap.inverseBidiMap();Commons Codec
编码解码工具。
Maven 依赖
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.17.1</version>
</dependency>Base64
import org.apache.commons.codec.binary.Base64;
// 编码
String encoded = Base64.encodeBase64String("Hello".getBytes());
// 解码
byte[] decoded = Base64.decodeBase64(encoded);
// URL 安全的 Base64
String urlSafe = Base64.encodeBase64URLSafeString(bytes);Hex
import org.apache.commons.codec.binary.Hex;
// 十六进制编码
String hex = Hex.encodeHexString(bytes);
byte[] bytes = Hex.decodeHex(hex);哈希算法
import org.apache.commons.codec.digest.DigestUtils;
String data = "password";
// MD5(不推荐用于密码存储)
String md5 = DigestUtils.md5Hex(data);
// SHA 系列
String sha256 = DigestUtils.sha256Hex(data);
String sha384 = DigestUtils.sha384Hex(data);
String sha512 = DigestUtils.sha512Hex(data);
// 文件哈希
String fileHash = DigestUtils.sha256Hex(new FileInputStream(file));URL 编码
import org.apache.commons.codec.net.URLCodec;
URLCodec codec = new URLCodec();
String encoded = codec.encode("Hello World"); // "Hello+World"
String decoded = codec.decode(encoded);Commons Text
文本处理增强工具。
Maven 依赖
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.12.0</version>
</dependency>字符串替换
import org.apache.commons.text.StringSubstitutor;
import org.apache.commons.text.StringTokenizer;
import org.apache.commons.text.TextStringBuilder;
// 变量替换
Map<String, String> values = new HashMap<>();
values.put("name", "World");
StringSubstitutor sub = new StringSubstitutor(values);
String result = sub.replace("Hello ${name}!"); // "Hello World!"
// 字符串构建器
TextStringBuilder builder = new TextStringBuilder();
builder.append("Hello").append(" ").append("World");
builder.appendln("!");
String result = builder.toString();字符串相似度
import org.apache.commons.text.similarity.LevenshteinDistance;
import org.apache.commons.text.similarity.JaccardSimilarity;
import org.apache.commons.text.similarity.FuzzyScore;
// Levenshtein 距离(编辑距离)
LevenshteinDistance levenshtein = new LevenshteinDistance();
int distance = levenshtein.apply("kitten", "sitting"); // 3
// Jaccard 相似度
JaccardSimilarity jaccard = new JaccardSimilarity();
double similarity = jaccard.apply("hello", "hallo"); // 0.75
// 模糊匹配分数
FuzzyScore fuzzy = new FuzzyScore(Locale.ENGLISH);
int score = fuzzy.fuzzyScore("hello", "hallo");WordUtils
import org.apache.commons.text.WordUtils;
// 首字母大写
WordUtils.capitalize("hello world"); // "Hello World"
WordUtils.capitalizeFully("HELLO WORLD"); // "Hello World"
// 缩写
WordUtils.abbreviate("Hello World", 8); // "Hello..."
// 换行
String wrapped = WordUtils.wrap("Long text here", 10);Commons CLI
命令行参数解析。
Maven 依赖
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.9.0</version>
</dependency>使用示例
import org.apache.commons.cli.*;
// 定义选项
Options options = new Options();
options.addOption("h", "help", false, "显示帮助信息");
options.addOption("f", "file", true, "输入文件路径");
options.addOption("v", "verbose", false, "详细输出");
options.addOption(Option.builder("o")
.longOpt("output")
.hasArg()
.argName("FILE")
.desc("输出文件路径")
.build());
// 解析参数
CommandLineParser parser = new DefaultParser();
try {
CommandLine cmd = parser.parse(options, args);
if (cmd.hasOption("h")) {
HelpFormatter formatter = new HelpFormatter();
formatter.printHelp("myapp", options);
return;
}
String inputFile = cmd.getOptionValue("f");
String outputFile = cmd.getOptionValue("o", "output.txt");
boolean verbose = cmd.hasOption("v");
} catch (ParseException e) {
System.err.println("参数解析失败: " + e.getMessage());
}Commons Pool
对象池实现。
Maven 依赖
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.12.1</version>
</dependency>对象池示例
import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.commons.pool2.impl.GenericObjectPool;
// 定义对象工厂
class ExpensiveObjectFactory extends BasePooledObjectFactory<ExpensiveObject> {
@Override
public ExpensiveObject create() {
return new ExpensiveObject(); // 创建昂贵对象
}
@Override
public PooledObject<ExpensiveObject> wrap(ExpensiveObject obj) {
return new DefaultPooledObject<>(obj);
}
@Override
public void destroyObject(PooledObject<ExpensiveObject> p) {
p.getObject().cleanup(); // 清理资源
}
}
// 使用对象池
GenericObjectPool<ExpensiveObject> pool = new GenericObjectPool<>(new ExpensiveObjectFactory());
pool.setMaxTotal(10);
pool.setMaxIdle(5);
try {
ExpensiveObject obj = pool.borrowObject();
try {
obj.doSomething();
} finally {
pool.returnObject(obj); // 归还对象
}
} catch (Exception e) {
// 处理异常
}最佳实践
1. 选择正确的库
| 需求 | 推荐库 |
|---|---|
| 字符串/对象工具 | Commons Lang3 |
| 文件/IO 操作 | Commons IO |
| 集合增强 | Commons Collections4 |
| 编码解码 | Commons Codec |
| 文本处理 | Commons Text |
| 命令行解析 | Commons CLI |
| 对象池 | Commons Pool2 |
2. 与 Java 8+ 特性结合
// 结合 Stream API
List<String> filtered = list.stream()
.filter(StringUtils::isNotBlank)
.map(String::trim)
.collect(Collectors.toList());
// 结合 Optional
Optional.ofNullable(value)
.filter(StringUtils::isNotBlank)
.orElseGet(() -> defaultValue);3. 注意事项
- 线程安全:大多数工具类是线程安全的,但要注意实例方法
- 空值处理:Commons 工具方法通常对 null 友好,但阅读文档确认
- 性能考量:对于高频调用,考虑直接使用 JDK 方法或缓存结果
- 版本兼容:Lang3 与 Lang2 不兼容,使用
lang3版本
总结
Apache Commons 系列库是 Java 开发的基础设施,它们:
- 减少样板代码:一行代码完成复杂操作
- 处理边界情况:null 安全、空集合处理
- 经过生产验证:数百万项目的依赖
- 持续维护:活跃的社区支持
建议:在项目中优先使用这些成熟工具,而非重复造轮子。但也要注意不要过度依赖,对于简单场景 JDK 原生方法可能更合适。





