搜 索

apache-commons包总结

  • 38阅读
  • 2022年05月12日
  • 0评论
首页 / 编程 / 正文

前言:为什么需要Apache Commons?

如果你写Java时经常遇到这些场景:

  1. 判断字符串是否为空,写了一堆 str != null && !str.isEmpty()
  2. 复制对象属性,写了几十行getter/setter
  3. 读取文件内容,try-catch-finally嵌套三层
  4. 集合操作,各种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

1.1 版本选择指南

组件最新稳定版JDK要求Maven坐标
commons-lang33.14.0JDK 8+org.apache.commons:commons-lang3
commons-collections44.4JDK 8+org.apache.commons:commons-collections4
commons-io2.15.1JDK 8+commons-io:commons-io
commons-codec1.16.0JDK 8+commons-codec:commons-codec
commons-beanutils1.9.4JDK 8+commons-beanutils:commons-beanutils
httpclient55.3JDK 8+org.apache.httpcomponents.client5:httpclient5

注意commons-langcommons-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()); // true

2.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);     // 1

2.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)
);  // true
flowchart 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.isBlankstr == null \\str.trim().isEmpty()相当
属性复制BeanUtilsMapStructMapStruct快10-100倍
集合操作CollectionUtilsStream APIStream更灵活
文件读取FileUtilsFiles.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开发的得力助手,但也要注意:

  1. 不要过度依赖:Java 8+已经提供了很多替代方案
  2. 注意版本:使用lang3collections4等新版本
  3. 性能敏感场景:BeanUtils等基于反射的工具要谨慎使用
  4. 保持更新:定期升级依赖,获取bug修复和性能优化
最后的最后:工具再好,也要知道它的边界。了解原理,才能用得更好!🚀
评论区
暂无评论
avatar