Apache Commons工具类

4 阅读22分钟

Apache Commons工具类

学习目标

  • 理解Apache Commons系列库的作用和价值
  • 掌握Commons Lang3的常用工具类(StringUtils、ObjectUtils等)
  • 熟练使用Commons Collections4进行集合操作
  • 掌握Commons IO进行文件和流操作
  • 掌握Commons BeanUtils进行对象操作
  • 了解其他常用Commons组件
  • 能够在实际项目中应用这些工具类提升开发效率

一、为什么需要Apache Commons?

1.1 Apache Commons简介

Apache Commons是Apache软件基金会的一个项目,提供了大量可重用的Java组件。这些组件经过充分测试,性能优秀,可以大大提高开发效率。

Apache Commons核心组件
├── Commons Lang3      - 核心工具类(字符串、对象、数组等)
├── Commons Collections4 - 集合工具类
├── Commons IO         - IO操作工具类
├── Commons BeanUtils  - Bean操作工具类
├── Commons Codec      - 编码解码工具类
├── Commons FileUpload - 文件上传工具类
└── Commons Math3      - 数学计算工具类

1.2 为什么要使用Commons?

问题场景:

// 场景1:判断字符串是否为空
// ❌ 原生写法:繁琐且容易出错
if (str != null && !str.trim().isEmpty()) {
    // 处理逻辑
}

// ✓ 使用Commons:简洁且安全
if (StringUtils.isNotBlank(str)) {
    // 处理逻辑
}

// 场景2:数组判空
// ❌ 原生写法
if (array != null && array.length > 0) {
    // 处理逻辑
}

// ✓ 使用Commons
if (ArrayUtils.isNotEmpty(array)) {
    // 处理逻辑
}

// 场景3:对象属性拷贝
// ❌ 原生写法:需要手动set每个属性
UserVO vo = new UserVO();
vo.setId(user.getId());
vo.setUsername(user.getUsername());
vo.setNickname(user.getNickname());
// ... 更多属性

// ✓ 使用Commons:一行代码搞定
BeanUtils.copyProperties(user, vo);

使用Commons的优势:

  1. 提高开发效率:减少重复代码,专注业务逻辑
  2. 代码更简洁:一行代码完成复杂操作
  3. 更加安全:处理了各种边界情况,避免NPE
  4. 性能优秀:经过充分优化和测试
  5. 社区支持:文档完善,使用广泛

1.3 Maven依赖配置

<!-- pom.xml -->
<dependencies>
    <!-- Commons Lang3 -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.12.0</version>
    </dependency>
    
    <!-- Commons Collections4 -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-collections4</artifactId>
        <version>4.4</version>
    </dependency>
    
    <!-- Commons IO -->
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.11.0</version>
    </dependency>
    
    <!-- Commons BeanUtils -->
    <dependency>
        <groupId>commons-beanutils</groupId>
        <artifactId>commons-beanutils</artifactId>
        <version>1.9.4</version>
    </dependency>
    
    <!-- Commons Codec -->
    <dependency>
        <groupId>commons-codec</groupId>
        <artifactId>commons-codec</artifactId>
        <version>1.15</version>
    </dependency>
</dependencies>

二、Commons Lang3 - 核心工具类

2.1 StringUtils - 字符串工具类

StringUtils是最常用的工具类之一,提供了大量字符串操作方法。

2.1.1 判空操作
import org.apache.commons.lang3.StringUtils;

public class StringUtilsDemo {
    public static void main(String[] args) {
        String str1 = null;
        String str2 = "";
        String str3 = "  ";
        String str4 = "hello";
        
        // isEmpty:判断是否为null或空字符串
        System.out.println(StringUtils.isEmpty(str1));    // true
        System.out.println(StringUtils.isEmpty(str2));    // true
        System.out.println(StringUtils.isEmpty(str3));    // false(空格不算空)
        System.out.println(StringUtils.isEmpty(str4));    // false
        
        // isBlank:判断是否为null、空字符串或只包含空白字符
        System.out.println(StringUtils.isBlank(str1));    // true
        System.out.println(StringUtils.isBlank(str2));    // true
        System.out.println(StringUtils.isBlank(str3));    // true(空格算空)
        System.out.println(StringUtils.isBlank(str4));    // false
        
        // isNotEmpty / isNotBlank:取反
        System.out.println(StringUtils.isNotEmpty(str4)); // true
        System.out.println(StringUtils.isNotBlank(str4)); // true
    }
}

isEmpty vs isBlank 对比:

┌──────────────┬──────────┬──────────┐
│   输入值     │ isEmpty  │ isBlank  │
├──────────────┼──────────┼──────────┤
│ nulltruetrue    │
│ ""truetrue    │
│ "  "falsetrue    │
│ "hello"falsefalse   │
└──────────────┴──────────┴──────────┘

使用建议:
- isEmpty:只判断null和空字符串
- isBlank:判断null、空字符串和空白字符(推荐使用)
2.1.2 默认值处理
// defaultString:如果为null则返回默认值
String str = null;
String result = StringUtils.defaultString(str);           // ""
String result2 = StringUtils.defaultString(str, "默认值"); // "默认值"

// defaultIfBlank:如果为blank则返回默认值
String str2 = "  ";
String result3 = StringUtils.defaultIfBlank(str2, "默认值"); // "默认值"

// defaultIfEmpty:如果为empty则返回默认值
String str3 = "";
String result4 = StringUtils.defaultIfEmpty(str3, "默认值"); // "默认值"

// 实际应用:处理用户输入
public String getUserNickname(String nickname) {
    // 如果用户没有输入昵称,使用默认昵称
    return StringUtils.defaultIfBlank(nickname, "匿名用户");
}
2.1.3 字符串截取和填充
// substring:安全的字符串截取(不会抛出IndexOutOfBoundsException)
String str = "hello world";
String sub1 = StringUtils.substring(str, 0, 5);    // "hello"
String sub2 = StringUtils.substring(str, 6);       // "world"
String sub3 = StringUtils.substring(str, 0, 100);  // "hello world"(不会越界)

// left/right/mid:从左/右/中间截取
String left = StringUtils.left(str, 5);      // "hello"
String right = StringUtils.right(str, 5);    // "world"
String mid = StringUtils.mid(str, 6, 5);     // "world"

// substringBefore/After:根据分隔符截取
String email = "user@example.com";
String username = StringUtils.substringBefore(email, "@");  // "user"
String domain = StringUtils.substringAfter(email, "@");     // "example.com"

// leftPad/rightPad:填充字符串到指定长度
String num = "123";
String padded1 = StringUtils.leftPad(num, 6, '0');   // "000123"
String padded2 = StringUtils.rightPad(num, 6, '0');  // "123000"

// center:居中对齐
String centered = StringUtils.center("hello", 11, '*'); // "***hello***"
2.1.4 字符串比较
// equals:安全的字符串比较(处理null)
String str1 = null;
String str2 = "hello";
boolean result1 = StringUtils.equals(str1, str2);  // false(不会NPE)

// equalsIgnoreCase:忽略大小写比较
boolean result2 = StringUtils.equalsIgnoreCase("Hello", "hello"); // true

// equalsAny:判断是否等于任意一个值
boolean result3 = StringUtils.equalsAny("apple", "apple", "banana", "orange"); // true

// compare:字符串比较(处理null)
int result4 = StringUtils.compare(str1, str2);  // -1(null小于非null)

// 实际应用:验证用户输入
public boolean isValidStatus(String status) {
    // 判断状态是否为有效值
    return StringUtils.equalsAnyIgnoreCase(status, "ACTIVE", "INACTIVE", "PENDING");
}
2.1.5 字符串查找和替换
String str = "hello world, hello java";

// contains:判断是否包含子串
boolean contains1 = StringUtils.contains(str, "world");      // true
boolean contains2 = StringUtils.containsIgnoreCase(str, "WORLD"); // true

// containsAny:判断是否包含任意一个字符
boolean contains3 = StringUtils.containsAny(str, 'a', 'b', 'c'); // true(包含'a')

// indexOf/lastIndexOf:查找子串位置
int index1 = StringUtils.indexOf(str, "hello");      // 0
int index2 = StringUtils.lastIndexOf(str, "hello");  // 13

// replace:替换字符串
String replaced1 = StringUtils.replace(str, "hello", "hi");  // "hi world, hi java"

// replaceOnce:只替换第一个匹配项
String replaced2 = StringUtils.replaceOnce(str, "hello", "hi"); // "hi world, hello java"

// remove:删除子串
String removed = StringUtils.remove(str, "hello ");  // "world, java"

// 实际应用:敏感词过滤
public String filterSensitiveWords(String content) {
    String filtered = content;
    filtered = StringUtils.replace(filtered, "敏感词1", "***");
    filtered = StringUtils.replace(filtered, "敏感词2", "***");
    return filtered;
}
2.1.6 字符串分割和连接
// split:分割字符串(处理null和空字符串)
String str = "apple,banana,orange";
String[] arr1 = StringUtils.split(str, ",");  // ["apple", "banana", "orange"]

// 处理多个分隔符
String str2 = "apple,banana;orange";
String[] arr2 = StringUtils.split(str2, ",;"); // ["apple", "banana", "orange"]

// splitByWholeSeparator:按完整分隔符分割
String str3 = "apple::banana::orange";
String[] arr3 = StringUtils.splitByWholeSeparator(str3, "::"); 
// ["apple", "banana", "orange"]

// join:连接字符串数组
String[] array = {"apple", "banana", "orange"};
String joined1 = StringUtils.join(array, ",");  // "apple,banana,orange"

// join集合
List<String> list = Arrays.asList("apple", "banana", "orange");
String joined2 = StringUtils.join(list, ",");   // "apple,banana,orange"

// 实际应用:构建SQL的IN子句
public String buildInClause(List<Long> ids) {
    if (CollectionUtils.isEmpty(ids)) {
        return "";
    }
    return "id IN (" + StringUtils.join(ids, ",") + ")";
}
2.1.7 字符串转换
// capitalize:首字母大写
String str1 = StringUtils.capitalize("hello");  // "Hello"

// uncapitalize:首字母小写
String str2 = StringUtils.uncapitalize("Hello"); // "hello"

// upperCase/lowerCase:大小写转换(处理null)
String str3 = StringUtils.upperCase("hello");   // "HELLO"
String str4 = StringUtils.lowerCase("HELLO");   // "hello"

// swapCase:大小写互换
String str5 = StringUtils.swapCase("Hello World"); // "hELLO wORLD"

// reverse:反转字符串
String str6 = StringUtils.reverse("hello");     // "olleh"

// repeat:重复字符串
String str7 = StringUtils.repeat("*", 5);       // "*****"
String str8 = StringUtils.repeat("ab", 3);      // "ababab"

// 实际应用:生成分隔线
public String generateSeparator(int length) {
    return StringUtils.repeat("-", length);
}

2.2 ObjectUtils - 对象工具类

import org.apache.commons.lang3.ObjectUtils;

public class ObjectUtilsDemo {
    public static void main(String[] args) {
        // defaultIfNull:如果为null则返回默认值
        String str = null;
        String result = ObjectUtils.defaultIfNull(str, "默认值"); // "默认值"
        
        // isEmpty:判断对象是否为空
        System.out.println(ObjectUtils.isEmpty(null));        // true
        System.out.println(ObjectUtils.isEmpty(""));          // true
        System.out.println(ObjectUtils.isEmpty(new int[0])); // true
        System.out.println(ObjectUtils.isEmpty("hello"));     // false
        
        // isNotEmpty:判断对象是否非空
        System.out.println(ObjectUtils.isNotEmpty("hello")); // true
        
        // compare:比较两个对象
        Integer a = 10;
        Integer b = 20;
        int result2 = ObjectUtils.compare(a, b);  // -1(a < b)
        
        // min/max:获取最小/最大值
        Integer min = ObjectUtils.min(10, 20, 5, 30);  // 5
        Integer max = ObjectUtils.max(10, 20, 5, 30);  // 30
        
        // clone:克隆对象(对象需要实现Cloneable接口)
        User user = new User("张三", 20);
        User cloned = ObjectUtils.clone(user);
    }
}

// 实际应用:处理可能为null的对象
public class UserService {
    public String getUserNickname(User user) {
        // 如果user为null或nickname为null,返回默认昵称
        return ObjectUtils.defaultIfNull(
            user != null ? user.getNickname() : null,
            "匿名用户"
        );
    }
    
    public int getUserAge(User user) {
        // 如果user为null或age为null,返回默认年龄
        Integer age = user != null ? user.getAge() : null;
        return ObjectUtils.defaultIfNull(age, 0);
    }
}

2.3 ArrayUtils - 数组工具类

import org.apache.commons.lang3.ArrayUtils;

public class ArrayUtilsDemo {
    public static void main(String[] args) {
        // isEmpty/isNotEmpty:判断数组是否为空
        int[] arr1 = null;
        int[] arr2 = new int[0];
        int[] arr3 = {1, 2, 3};
        
        System.out.println(ArrayUtils.isEmpty(arr1));    // true
        System.out.println(ArrayUtils.isEmpty(arr2));    // true
        System.out.println(ArrayUtils.isEmpty(arr3));    // false
        System.out.println(ArrayUtils.isNotEmpty(arr3)); // true
        
        // contains:判断数组是否包含某个元素
        boolean contains = ArrayUtils.contains(arr3, 2);  // true
        
        // indexOf:查找元素位置
        int index = ArrayUtils.indexOf(arr3, 2);  // 1
        
        // add:添加元素(返回新数组)
        int[] arr4 = ArrayUtils.add(arr3, 4);  // {1, 2, 3, 4}
        
        // addAll:合并数组
        int[] arr5 = {4, 5, 6};
        int[] arr6 = ArrayUtils.addAll(arr3, arr5);  // {1, 2, 3, 4, 5, 6}
        
        // remove:删除指定位置的元素
        int[] arr7 = ArrayUtils.remove(arr3, 1);  // {1, 3}
        
        // removeElement:删除指定元素
        int[] arr8 = ArrayUtils.removeElement(arr3, 2);  // {1, 3}
        
        // reverse:反转数组
        int[] arr9 = {1, 2, 3, 4, 5};
        ArrayUtils.reverse(arr9);  // {5, 4, 3, 2, 1}
        
        // subarray:截取子数组
        int[] arr10 = ArrayUtils.subarray(arr3, 0, 2);  // {1, 2}
        
        // toString:数组转字符串
        String str = ArrayUtils.toString(arr3);  // "{1,2,3}"
        
        // toObject/toPrimitive:基本类型数组和包装类型数组互转
        int[] primitiveArray = {1, 2, 3};
        Integer[] objectArray = ArrayUtils.toObject(primitiveArray);
        int[] primitiveArray2 = ArrayUtils.toPrimitive(objectArray);
    }
}

// 实际应用:处理数组参数
public class ProductService {
    public List<Product> findByIds(Long[] ids) {
        // 判断数组是否为空
        if (ArrayUtils.isEmpty(ids)) {
            return Collections.emptyList();
        }
        
        // 查询数据库
        return productMapper.selectByIds(Arrays.asList(ids));
    }
    
    public List<Product> findByCategories(String... categories) {
        // 判断可变参数是否为空
        if (ArrayUtils.isEmpty(categories)) {
            return Collections.emptyList();
        }
        
        // 查询数据库
        return productMapper.selectByCategories(Arrays.asList(categories));
    }
}

2.4 NumberUtils - 数字工具类

import org.apache.commons.lang3.math.NumberUtils;

public class NumberUtilsDemo {
    public static void main(String[] args) {
        // toInt/toLong/toFloat/toDouble:字符串转数字(安全转换)
        int num1 = NumberUtils.toInt("123");        // 123
        int num2 = NumberUtils.toInt("abc");        // 0(转换失败返回0)
        int num3 = NumberUtils.toInt("abc", -1);    // -1(转换失败返回默认值)
        
        long num4 = NumberUtils.toLong("123456");   // 123456
        float num5 = NumberUtils.toFloat("123.45"); // 123.45
        double num6 = NumberUtils.toDouble("123.45"); // 123.45
        
        // isDigits:判断字符串是否全为数字
        boolean isDigits1 = NumberUtils.isDigits("123");   // true
        boolean isDigits2 = NumberUtils.isDigits("12.3");  // false
        boolean isDigits3 = NumberUtils.isDigits("abc");   // false
        
        // isCreatable:判断字符串是否可以转换为数字
        boolean isCreatable1 = NumberUtils.isCreatable("123");    // true
        boolean isCreatable2 = NumberUtils.isCreatable("12.3");   // true
        boolean isCreatable3 = NumberUtils.isCreatable("0x10");   // true(十六进制)
        boolean isCreatable4 = NumberUtils.isCreatable("abc");    // false
        
        // min/max:获取最小/最大值
        int min = NumberUtils.min(10, 20, 5, 30);  // 5
        int max = NumberUtils.max(10, 20, 5, 30);  // 30
        
        // compare:比较两个数字
        int result = NumberUtils.compare(10, 20);  // -1(10 < 20)
    }
}

// 实际应用:处理用户输入的数字
public class OrderService {
    public void createOrder(String quantityStr, String priceStr) {
        // 安全地将字符串转换为数字
        int quantity = NumberUtils.toInt(quantityStr, 1);  // 默认数量为1
        double price = NumberUtils.toDouble(priceStr, 0.0); // 默认价格为0
        
        // 验证数字是否有效
        if (quantity <= 0 || price <= 0) {
            throw new IllegalArgumentException("数量和价格必须大于0");
        }
        
        // 创建订单
        Order order = new Order();
        order.setQuantity(quantity);
        order.setPrice(price);
        order.setTotalAmount(quantity * price);
        orderMapper.insert(order);
    }
}

2.5 RandomUtils - 随机数工具类

import org.apache.commons.lang3.RandomUtils;

public class RandomUtilsDemo {
    public static void main(String[] args) {
        // nextInt:生成随机整数
        int randomInt1 = RandomUtils.nextInt();           // 随机int
        int randomInt2 = RandomUtils.nextInt(1, 100);     // 1到99之间的随机数
        
        // nextLong:生成随机长整数
        long randomLong = RandomUtils.nextLong(1L, 1000L);
        
        // nextDouble:生成随机浮点数
        double randomDouble = RandomUtils.nextDouble(0.0, 1.0);
        
        // nextBoolean:生成随机布尔值
        boolean randomBoolean = RandomUtils.nextBoolean();
        
        // nextBytes:生成随机字节数组
        byte[] randomBytes = RandomUtils.nextBytes(16);
    }
}

// 实际应用:生成随机验证码
public class SmsService {
    public String generateVerificationCode() {
        // 生成6位随机验证码
        int code = RandomUtils.nextInt(100000, 999999);
        return String.valueOf(code);
    }
    
    public String generateOrderNo() {
        // 生成订单号:时间戳 + 6位随机数
        long timestamp = System.currentTimeMillis();
        int random = RandomUtils.nextInt(100000, 999999);
        return timestamp + String.valueOf(random);
    }
}

三、Commons Collections4 - 集合工具类

3.1 CollectionUtils - 集合工具类

import org.apache.commons.collections4.CollectionUtils;

public class CollectionUtilsDemo {
    public static void main(String[] args) {
        List<String> list1 = Arrays.asList("a", "b", "c");
        List<String> list2 = Arrays.asList("b", "c", "d");
        
        // isEmpty/isNotEmpty:判断集合是否为空
        System.out.println(CollectionUtils.isEmpty(null));        // true
        System.out.println(CollectionUtils.isEmpty(new ArrayList<>())); // true
        System.out.println(CollectionUtils.isNotEmpty(list1));   // true
        
        // union:并集
        Collection<String> union = CollectionUtils.union(list1, list2);
        // [a, b, c, d]
        
        // intersection:交集
        Collection<String> intersection = CollectionUtils.intersection(list1, list2);
        // [b, c]
        
        // disjunction:差集(对称差集)
        Collection<String> disjunction = CollectionUtils.disjunction(list1, list2);
        // [a, d]
        
        // subtract:差集(list1 - list2)
        Collection<String> subtract = CollectionUtils.subtract(list1, list2);
        // [a]
        
        // isEqualCollection:判断两个集合是否相等(忽略顺序)
        boolean isEqual = CollectionUtils.isEqualCollection(list1, list2); // false
        
        // containsAny:判断是否包含任意一个元素
        boolean containsAny = CollectionUtils.containsAny(list1, list2); // true
        
        // containsAll:判断是否包含所有元素
        boolean containsAll = CollectionUtils.containsAll(list1, list2); // false
        
        // addAll:添加所有元素
        List<String> list3 = new ArrayList<>();
        CollectionUtils.addAll(list3, "a", "b", "c");
        
        // filter:过滤集合
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
        CollectionUtils.filter(numbers, num -> num % 2 == 0);
        // numbers现在是[2, 4, 6]
        
        // select:选择符合条件的元素(返回新集合)
        Collection<Integer> evenNumbers = CollectionUtils.select(
            Arrays.asList(1, 2, 3, 4, 5, 6),
            num -> num % 2 == 0
        );
        // [2, 4, 6]
        
        // transform:转换集合元素
        Collection<String> transformed = CollectionUtils.collect(
            Arrays.asList(1, 2, 3),
            num -> "num_" + num
        );
        // ["num_1", "num_2", "num_3"]
    }
}

// 实际应用:处理集合操作
public class UserService {
    public List<User> findCommonFriends(Long userId1, Long userId2) {
        // 获取两个用户的好友列表
        List<User> friends1 = userMapper.selectFriendsByUserId(userId1);
        List<User> friends2 = userMapper.selectFriendsByUserId(userId2);
        
        // 判断是否为空
        if (CollectionUtils.isEmpty(friends1) || CollectionUtils.isEmpty(friends2)) {
            return Collections.emptyList();
        }
        
        // 获取共同好友(交集)
        Collection<User> commonFriends = CollectionUtils.intersection(friends1, friends2);
        return new ArrayList<>(commonFriends);
    }
    
    public List<User> findActiveUsers(List<User> users) {
        // 判断集合是否为空
        if (CollectionUtils.isEmpty(users)) {
            return Collections.emptyList();
        }
        
        // 过滤出活跃用户
        return CollectionUtils.select(users, user -> "ACTIVE".equals(user.getStatus()))
                              .stream()
                              .collect(Collectors.toList());
    }
}

3.2 MapUtils - Map工具类

import org.apache.commons.collections4.MapUtils;

public class MapUtilsDemo {
    public static void main(String[] args) {
        Map<String, Object> map = new HashMap<>();
        map.put("name", "张三");
        map.put("age", 20);
        map.put("score", 85.5);
        
        // isEmpty/isNotEmpty:判断Map是否为空
        System.out.println(MapUtils.isEmpty(null));        // true
        System.out.println(MapUtils.isEmpty(new HashMap<>())); // true
        System.out.println(MapUtils.isNotEmpty(map));     // true
        
        // getString:获取String类型的值
        String name = MapUtils.getString(map, "name");     // "张三"
        String gender = MapUtils.getString(map, "gender", "未知"); // "未知"(默认值)
        
        // getInteger:获取Integer类型的值
        Integer age = MapUtils.getInteger(map, "age");     // 20
        Integer height = MapUtils.getInteger(map, "height", 170); // 170(默认值)
        
        // getDouble:获取Double类型的值
        Double score = MapUtils.getDouble(map, "score");   // 85.5
        
        // getBoolean:获取Boolean类型的值
        Boolean isActive = MapUtils.getBoolean(map, "isActive", true); // true(默认值)
        
        // getLong:获取Long类型的值
        Long id = MapUtils.getLong(map, "id", 0L);         // 0L(默认值)
        
        // safeAddToMap:安全地添加元素到Map
        MapUtils.safeAddToMap(map, "city", "北京");
        
        // invertMap:反转Map(key和value互换)
        Map<String, Integer> original = new HashMap<>();
        original.put("apple", 1);
        original.put("banana", 2);
        Map<Integer, String> inverted = MapUtils.invertMap(original);
        // {1=apple, 2=banana}
        
        // debugPrint:打印Map内容(用于调试)
        MapUtils.debugPrint(System.out, "用户信息", map);
    }
}

// 实际应用:处理配置参数
public class ConfigService {
    public void processConfig(Map<String, Object> config) {
        // 判断配置是否为空
        if (MapUtils.isEmpty(config)) {
            throw new IllegalArgumentException("配置不能为空");
        }
        
        // 安全地获取配置值
        String appName = MapUtils.getString(config, "app.name", "默认应用");
        Integer port = MapUtils.getInteger(config, "server.port", 8080);
        Boolean enableCache = MapUtils.getBoolean(config, "cache.enabled", false);
        
        // 使用配置
        System.out.println("应用名称:" + appName);
        System.out.println("端口:" + port);
        System.out.println("是否启用缓存:" + enableCache);
    }
}

3.3 ListUtils - List工具类

import org.apache.commons.collections4.ListUtils;

public class ListUtilsDemo {
    public static void main(String[] args) {
        List<Integer> list1 = Arrays.asList(1, 2, 3, 4, 5);
        List<Integer> list2 = Arrays.asList(4, 5, 6, 7, 8);
        
        // union:并集
        List<Integer> union = ListUtils.union(list1, list2);
        // [1, 2, 3, 4, 5, 4, 5, 6, 7, 8](保留重复元素)
        
        // intersection:交集
        List<Integer> intersection = ListUtils.intersection(list1, list2);
        // [4, 5]
        
        // subtract:差集
        List<Integer> subtract = ListUtils.subtract(list1, list2);
        // [1, 2, 3]
        
        // partition:分区(将大List分成多个小List)
        List<Integer> bigList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        List<List<Integer>> partitions = ListUtils.partition(bigList, 3);
        // [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
        
        // defaultIfNull:如果为null则返回空List
        List<String> list3 = null;
        List<String> result = ListUtils.defaultIfNull(list3, Collections.emptyList());
        
        // emptyIfNull:如果为null则返回空List
        List<String> result2 = ListUtils.emptyIfNull(list3);
    }
}

// 实际应用:批量处理数据
public class OrderService {
    public void batchProcessOrders(List<Order> orders) {
        // 判断订单列表是否为空
        if (CollectionUtils.isEmpty(orders)) {
            return;
        }
        
        // 将订单列表分成每批100个
        List<List<Order>> batches = ListUtils.partition(orders, 100);
        
        // 批量处理每一批订单
        for (List<Order> batch : batches) {
            processBatch(batch);
        }
    }
    
    private void processBatch(List<Order> batch) {
        // 批量更新订单状态
        orderMapper.batchUpdate(batch);
    }
}

四、Commons IO - IO操作工具类

4.1 FileUtils - 文件工具类

import org.apache.commons.io.FileUtils;

public class FileUtilsDemo {
    public static void main(String[] args) throws IOException {
        File file = new File("test.txt");
        File dir = new File("testDir");
        
        // readFileToString:读取文件内容为字符串
        String content = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
        
        // readLines:读取文件内容为行列表
        List<String> lines = FileUtils.readLines(file, StandardCharsets.UTF_8);
        
        // writeStringToFile:写入字符串到文件
        FileUtils.writeStringToFile(file, "Hello World", StandardCharsets.UTF_8);
        
        // writeLines:写入行列表到文件
        List<String> linesToWrite = Arrays.asList("line1", "line2", "line3");
        FileUtils.writeLines(file, linesToWrite);
        
        // copyFile:复制文件
        File destFile = new File("test_copy.txt");
        FileUtils.copyFile(file, destFile);
        
        // copyDirectory:复制目录
        File destDir = new File("testDir_copy");
        FileUtils.copyDirectory(dir, destDir);
        
        // moveFile:移动文件
        File movedFile = new File("test_moved.txt");
        FileUtils.moveFile(file, movedFile);
        
        // deleteQuietly:删除文件(不抛异常)
        FileUtils.deleteQuietly(file);
        
        // deleteDirectory:删除目录
        FileUtils.deleteDirectory(dir);
        
        // sizeOf:获取文件大小
        long size = FileUtils.sizeOf(file);
        
        // sizeOfDirectory:获取目录大小
        long dirSize = FileUtils.sizeOfDirectory(dir);
        
        // listFiles:列出目录下的文件
        Collection<File> files = FileUtils.listFiles(
            dir,
            new String[]{"txt", "java"},  // 文件扩展名
            true  // 是否递归
        );
        
        // touch:创建文件(如果不存在)或更新修改时间
        FileUtils.touch(file);
        
        // forceMkdir:强制创建目录
        FileUtils.forceMkdir(dir);
    }
}

// 实际应用:文件操作
public class FileService {
    private static final String UPLOAD_DIR = "/data/uploads/";
    
    public void saveFile(MultipartFile file, String filename) throws IOException {
        // 创建上传目录
        File uploadDir = new File(UPLOAD_DIR);
        FileUtils.forceMkdir(uploadDir);
        
        // 保存文件
        File destFile = new File(uploadDir, filename);
        FileUtils.copyInputStreamToFile(file.getInputStream(), destFile);
    }
    
    public String readFileContent(String filename) throws IOException {
        File file = new File(UPLOAD_DIR + filename);
        
        // 判断文件是否存在
        if (!file.exists()) {
            throw new FileNotFoundException("文件不存在:" + filename);
        }
        
        // 读取文件内容
        return FileUtils.readFileToString(file, StandardCharsets.UTF_8);
    }
    
    public void deleteFile(String filename) {
        File file = new File(UPLOAD_DIR + filename);
        // 安全删除文件(不抛异常)
        FileUtils.deleteQuietly(file);
    }
    
    public long getDirectorySize() {
        File dir = new File(UPLOAD_DIR);
        // 获取目录大小
        return FileUtils.sizeOfDirectory(dir);
    }
}

4.2 IOUtils - IO流工具类

import org.apache.commons.io.IOUtils;

public class IOUtilsDemo {
    public static void main(String[] args) throws IOException {
        // toString:将InputStream转换为字符串
        InputStream is = new FileInputStream("test.txt");
        String content = IOUtils.toString(is, StandardCharsets.UTF_8);
        IOUtils.closeQuietly(is);
        
        // toByteArray:将InputStream转换为字节数组
        is = new FileInputStream("test.txt");
        byte[] bytes = IOUtils.toByteArray(is);
        IOUtils.closeQuietly(is);
        
        // copy:复制流
        InputStream input = new FileInputStream("source.txt");
        OutputStream output = new FileOutputStream("dest.txt");
        IOUtils.copy(input, output);
        IOUtils.closeQuietly(input, output);
        
        // readLines:读取流内容为行列表
        is = new FileInputStream("test.txt");
        List<String> lines = IOUtils.readLines(is, StandardCharsets.UTF_8);
        IOUtils.closeQuietly(is);
        
        // writeLines:写入行列表到流
        OutputStream os = new FileOutputStream("test.txt");
        List<String> linesToWrite = Arrays.asList("line1", "line2", "line3");
        IOUtils.writeLines(linesToWrite, "\n", os, StandardCharsets.UTF_8);
        IOUtils.closeQuietly(os);
        
        // closeQuietly:安全关闭流(不抛异常)
        IOUtils.closeQuietly(is, os);
    }
}

// 实际应用:处理HTTP响应流
public class HttpService {
    public String downloadContent(String url) throws IOException {
        HttpURLConnection conn = null;
        InputStream is = null;
        
        try {
            conn = (HttpURLConnection) new URL(url).openConnection();
            conn.setRequestMethod("GET");
            conn.connect();
            
            is = conn.getInputStream();
            // 将响应流转换为字符串
            return IOUtils.toString(is, StandardCharsets.UTF_8);
        } finally {
            // 安全关闭流
            IOUtils.closeQuietly(is);
            if (conn != null) {
                conn.disconnect();
            }
        }
    }
    
    public void downloadFile(String url, String destFile) throws IOException {
        HttpURLConnection conn = null;
        InputStream is = null;
        OutputStream os = null;
        
        try {
            conn = (HttpURLConnection) new URL(url).openConnection();
            conn.setRequestMethod("GET");
            conn.connect();
            
            is = conn.getInputStream();
            os = new FileOutputStream(destFile);
            
            // 复制流
            IOUtils.copy(is, os);
        } finally {
            // 安全关闭流
            IOUtils.closeQuietly(is, os);
            if (conn != null) {
                conn.disconnect();
            }
        }
    }
}

4.3 FilenameUtils - 文件名工具类

import org.apache.commons.io.FilenameUtils;

public class FilenameUtilsDemo {
    public static void main(String[] args) {
        String filename = "/home/user/documents/test.txt";
        
        // getName:获取文件名
        String name = FilenameUtils.getName(filename);  // "test.txt"
        
        // getBaseName:获取文件名(不含扩展名)
        String baseName = FilenameUtils.getBaseName(filename);  // "test"
        
        // getExtension:获取文件扩展名
        String extension = FilenameUtils.getExtension(filename);  // "txt"
        
        // getPath:获取文件路径(不含文件名)
        String path = FilenameUtils.getPath(filename);  // "/home/user/documents/"
        
        // getFullPath:获取完整路径(不含文件名)
        String fullPath = FilenameUtils.getFullPath(filename);  // "/home/user/documents/"
        
        // normalize:规范化路径
        String normalized = FilenameUtils.normalize("/home/user/../user/documents/./test.txt");
        // "/home/user/documents/test.txt"
        
        // concat:连接路径
        String concatenated = FilenameUtils.concat("/home/user", "documents/test.txt");
        // "/home/user/documents/test.txt"
        
        // removeExtension:移除扩展名
        String noExt = FilenameUtils.removeExtension(filename);
        // "/home/user/documents/test"
        
        // isExtension:判断是否为指定扩展名
        boolean isTxt = FilenameUtils.isExtension(filename, "txt");  // true
        boolean isImage = FilenameUtils.isExtension(filename, new String[]{"jpg", "png", "gif"});  // false
    }
}

// 实际应用:文件上传处理
public class FileUploadService {
    private static final List<String> ALLOWED_EXTENSIONS = 
        Arrays.asList("jpg", "jpeg", "png", "gif", "pdf", "doc", "docx");
    
    public String uploadFile(MultipartFile file) throws IOException {
        // 获取原始文件名
        String originalFilename = file.getOriginalFilename();
        
        // 获取文件扩展名
        String extension = FilenameUtils.getExtension(originalFilename);
        
        // 验证文件扩展名
        if (!ALLOWED_EXTENSIONS.contains(extension.toLowerCase())) {
            throw new IllegalArgumentException("不支持的文件类型:" + extension);
        }
        
        // 生成新文件名:UUID + 扩展名
        String newFilename = UUID.randomUUID().toString() + "." + extension;
        
        // 保存文件
        String uploadPath = "/data/uploads/";
        File destFile = new File(uploadPath + newFilename);
        FileUtils.copyInputStreamToFile(file.getInputStream(), destFile);
        
        return newFilename;
    }
}

五、Commons BeanUtils - Bean操作工具类

5.1 BeanUtils - Bean属性操作

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;

public class BeanUtilsDemo {
    public static void main(String[] args) throws Exception {
        User user = new User();
        user.setId(1L);
        user.setUsername("zhangsan");
        user.setAge(20);
        
        // copyProperties:复制属性
        UserVO vo = new UserVO();
        BeanUtils.copyProperties(vo, user);
        // vo现在拥有user的所有属性值
        
        // getProperty:获取属性值(返回String)
        String username = BeanUtils.getProperty(user, "username");  // "zhangsan"
        String age = BeanUtils.getProperty(user, "age");  // "20"(注意是String)
        
        // setProperty:设置属性值(自动类型转换)
        BeanUtils.setProperty(user, "age", "25");  // 字符串"25"会自动转换为int
        
        // describe:将Bean转换为Map
        Map<String, String> map = BeanUtils.describe(user);
        // {id=1, username=zhangsan, age=25, class=class User}
        
        // populate:从Map填充Bean
        Map<String, Object> properties = new HashMap<>();
        properties.put("username", "lisi");
        properties.put("age", 30);
        BeanUtils.populate(user, properties);
        
        // cloneBean:克隆Bean
        User cloned = (User) BeanUtils.cloneBean(user);
    }
}

// PropertyUtils:更强大的属性操作(保留类型)
public class PropertyUtilsDemo {
    public static void main(String[] args) throws Exception {
        User user = new User();
        
        // getProperty:获取属性值(保留原始类型)
        Integer age = (Integer) PropertyUtils.getProperty(user, "age");
        
        // setProperty:设置属性值(不进行类型转换)
        PropertyUtils.setProperty(user, "age", 25);  // 必须传入Integer类型
        
        // getPropertyType:获取属性类型
        Class<?> ageType = PropertyUtils.getPropertyType(user, "age");  // Integer.class
        
        // isReadable/isWriteable:判断属性是否可读/可写
        boolean readable = PropertyUtils.isReadable(user, "username");  // true
        boolean writeable = PropertyUtils.isWriteable(user, "username"); // true
    }
}

// 实际应用:DTO和Entity互转
public class UserService {
    public UserVO convertToVO(User user) {
        if (user == null) {
            return null;
        }
        
        UserVO vo = new UserVO();
        try {
            // 复制属性
            BeanUtils.copyProperties(vo, user);
        } catch (Exception e) {
            log.error("属性复制失败", e);
            throw new RuntimeException("属性复制失败", e);
        }
        
        return vo;
    }
    
    public User convertToEntity(UserDTO dto) {
        if (dto == null) {
            return null;
        }
        
        User user = new User();
        try {
            // 复制属性
            BeanUtils.copyProperties(user, dto);
        } catch (Exception e) {
            log.error("属性复制失败", e);
            throw new RuntimeException("属性复制失败", e);
        }
        
        return user;
    }
    
    public void updateUser(Long userId, Map<String, Object> updates) {
        // 查询用户
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new UserNotFoundException("用户不存在");
        }
        
        try {
            // 从Map更新Bean属性
            BeanUtils.populate(user, updates);
            
            // 更新数据库
            userMapper.updateById(user);
        } catch (Exception e) {
            log.error("更新用户失败", e);
            throw new RuntimeException("更新用户失败", e);
        }
    }
}

六、Commons Codec - 编码解码工具类

6.1 DigestUtils - 摘要工具类

import org.apache.commons.codec.digest.DigestUtils;

public class DigestUtilsDemo {
    public static void main(String[] args) {
        String text = "hello world";
        
        // MD5加密
        String md5Hex = DigestUtils.md5Hex(text);
        System.out.println("MD5: " + md5Hex);
        
        // SHA-1加密
        String sha1Hex = DigestUtils.sha1Hex(text);
        System.out.println("SHA-1: " + sha1Hex);
        
        // SHA-256加密
        String sha256Hex = DigestUtils.sha256Hex(text);
        System.out.println("SHA-256: " + sha256Hex);
        
        // SHA-512加密
        String sha512Hex = DigestUtils.sha512Hex(text);
        System.out.println("SHA-512: " + sha512Hex);
    }
}

// 实际应用:密码加密和文件校验
public class SecurityService {
    public String encryptPassword(String password) {
        // 使用SHA-256加密密码
        return DigestUtils.sha256Hex(password);
    }
    
    public boolean verifyPassword(String inputPassword, String storedPassword) {
        // 加密输入的密码
        String encrypted = DigestUtils.sha256Hex(inputPassword);
        
        // 比较加密后的密码
        return encrypted.equals(storedPassword);
    }
    
    public String calculateFileMD5(File file) throws IOException {
        // 计算文件的MD5值
        try (FileInputStream fis = new FileInputStream(file)) {
            return DigestUtils.md5Hex(fis);
        }
    }
    
    public boolean verifyFileIntegrity(File file, String expectedMD5) throws IOException {
        // 验证文件完整性
        String actualMD5 = calculateFileMD5(file);
        return actualMD5.equalsIgnoreCase(expectedMD5);
    }
}

6.2 Base64 - Base64编码解码

import org.apache.commons.codec.binary.Base64;

public class Base64Demo {
    public static void main(String[] args) {
        String text = "hello world";
        
        // Base64编码
        String encoded = Base64.encodeBase64String(text.getBytes());
        System.out.println("编码后: " + encoded);  // "aGVsbG8gd29ybGQ="
        
        // Base64解码
        byte[] decoded = Base64.decodeBase64(encoded);
        String decodedText = new String(decoded);
        System.out.println("解码后: " + decodedText);  // "hello world"
        
        // URL安全的Base64编码
        String urlSafeEncoded = Base64.encodeBase64URLSafeString(text.getBytes());
        System.out.println("URL安全编码: " + urlSafeEncoded);
    }
}

// 实际应用:图片Base64编码
public class ImageService {
    public String imageToBase64(File imageFile) throws IOException {
        // 读取图片文件
        byte[] imageBytes = FileUtils.readFileToByteArray(imageFile);
        
        // Base64编码
        return Base64.encodeBase64String(imageBytes);
    }
    
    public void base64ToImage(String base64String, File destFile) throws IOException {
        // Base64解码
        byte[] imageBytes = Base64.decodeBase64(base64String);
        
        // 写入文件
        FileUtils.writeByteArrayToFile(destFile, imageBytes);
    }
    
    public String getImageDataUrl(File imageFile) throws IOException {
        // 获取文件扩展名
        String extension = FilenameUtils.getExtension(imageFile.getName());
        
        // Base64编码
        String base64 = imageToBase64(imageFile);
        
        // 返回Data URL格式
        return "data:image/" + extension + ";base64," + base64;
    }
}

七、实战案例

7.1 用户信息处理

public class UserInfoProcessor {
    /**
     * 处理用户注册信息
     */
    public User processRegistration(UserRegisterDTO dto) {
        // 1. 验证用户名不为空
        if (StringUtils.isBlank(dto.getUsername())) {
            throw new IllegalArgumentException("用户名不能为空");
        }
        
        // 2. 验证密码不为空且长度符合要求
        if (StringUtils.isBlank(dto.getPassword()) || dto.getPassword().length() < 6) {
            throw new IllegalArgumentException("密码不能为空且长度不能少于6位");
        }
        
        // 3. 用户名转小写
        String username = StringUtils.lowerCase(dto.getUsername());
        
        // 4. 昵称默认值处理
        String nickname = StringUtils.defaultIfBlank(dto.getNickname(), username);
        
        // 5. 密码加密
        String encryptedPassword = DigestUtils.sha256Hex(dto.getPassword());
        
        // 6. 创建用户对象
        User user = new User();
        user.setUsername(username);
        user.setPassword(encryptedPassword);
        user.setNickname(nickname);
        user.setCreateTime(new Date());
        
        return user;
    }
    
    /**
     * 批量导入用户
     */
    public List<User> batchImport(List<UserImportDTO> dtoList) {
        // 1. 验证列表不为空
        if (CollectionUtils.isEmpty(dtoList)) {
            throw new IllegalArgumentException("导入列表不能为空");
        }
        
        // 2. 过滤掉无效数据
        List<UserImportDTO> validList = CollectionUtils.select(
            dtoList,
            dto -> StringUtils.isNotBlank(dto.getUsername()) 
                && StringUtils.isNotBlank(dto.getPassword())
        ).stream().collect(Collectors.toList());
        
        // 3. 转换为User对象
        List<User> users = new ArrayList<>();
        for (UserImportDTO dto : validList) {
            User user = new User();
            try {
                BeanUtils.copyProperties(user, dto);
                user.setPassword(DigestUtils.sha256Hex(dto.getPassword()));
                users.add(user);
            } catch (Exception e) {
                log.error("属性复制失败", e);
            }
        }
        
        // 4. 分批插入数据库
        List<List<User>> batches = ListUtils.partition(users, 100);
        for (List<User> batch : batches) {
            userMapper.batchInsert(batch);
        }
        
        return users;
    }
}

7.2 文件处理

public class FileProcessor {
    private static final String UPLOAD_DIR = "/data/uploads/";
    private static final List<String> ALLOWED_EXTENSIONS = 
        Arrays.asList("jpg", "jpeg", "png", "gif", "pdf", "doc", "docx", "xls", "xlsx");
    
    /**
     * 处理文件上传
     */
    public FileInfo uploadFile(MultipartFile file) throws IOException {
        // 1. 验证文件不为空
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("文件不能为空");
        }
        
        // 2. 获取原始文件名
        String originalFilename = file.getOriginalFilename();
        if (StringUtils.isBlank(originalFilename)) {
            throw new IllegalArgumentException("文件名不能为空");
        }
        
        // 3. 获取文件扩展名
        String extension = FilenameUtils.getExtension(originalFilename);
        
        // 4. 验证文件类型
        if (!ALLOWED_EXTENSIONS.contains(extension.toLowerCase())) {
            throw new IllegalArgumentException("不支持的文件类型:" + extension);
        }
        
        // 5. 生成新文件名
        String newFilename = generateFilename(extension);
        
        // 6. 创建上传目录
        File uploadDir = new File(UPLOAD_DIR);
        FileUtils.forceMkdir(uploadDir);
        
        // 7. 保存文件
        File destFile = new File(uploadDir, newFilename);
        FileUtils.copyInputStreamToFile(file.getInputStream(), destFile);
        
        // 8. 计算文件MD5
        String md5 = DigestUtils.md5Hex(new FileInputStream(destFile));
        
        // 9. 返回文件信息
        FileInfo fileInfo = new FileInfo();
        fileInfo.setOriginalFilename(originalFilename);
        fileInfo.setFilename(newFilename);
        fileInfo.setExtension(extension);
        fileInfo.setSize(file.getSize());
        fileInfo.setMd5(md5);
        fileInfo.setUploadTime(new Date());
        
        return fileInfo;
    }
    
    /**
     * 生成文件名:日期 + UUID + 扩展名
     */
    private String generateFilename(String extension) {
        String date = new SimpleDateFormat("yyyyMMdd").format(new Date());
        String uuid = UUID.randomUUID().toString().replace("-", "");
        return date + "_" + uuid + "." + extension;
    }
    
    /**
     * 批量删除文件
     */
    public void batchDeleteFiles(List<String> filenames) {
        if (CollectionUtils.isEmpty(filenames)) {
            return;
        }
        
        for (String filename : filenames) {
            File file = new File(UPLOAD_DIR + filename);
            FileUtils.deleteQuietly(file);
        }
    }
    
    /**
     * 清理过期文件(7天前的文件)
     */
    public void cleanExpiredFiles() {
        File uploadDir = new File(UPLOAD_DIR);
        if (!uploadDir.exists()) {
            return;
        }
        
        // 获取7天前的时间
        long expireTime = System.currentTimeMillis() - 7 * 24 * 60 * 60 * 1000;
        
        // 列出所有文件
        Collection<File> files = FileUtils.listFiles(uploadDir, null, true);
        
        // 删除过期文件
        for (File file : files) {
            if (file.lastModified() < expireTime) {
                FileUtils.deleteQuietly(file);
                log.info("删除过期文件:{}", file.getName());
            }
        }
    }
}

7.3 数据导出

public class DataExporter {
    /**
     * 导出用户数据到CSV
     */
    public void exportUsersToCsv(List<User> users, File destFile) throws IOException {
        // 1. 验证数据不为空
        if (CollectionUtils.isEmpty(users)) {
            throw new IllegalArgumentException("导出数据不能为空");
        }
        
        // 2. 构建CSV内容
        List<String> lines = new ArrayList<>();
        
        // 添加表头
        lines.add("ID,用户名,昵称,年龄,创建时间");
        
        // 添加数据行
        for (User user : users) {
            String line = StringUtils.join(
                new Object[]{
                    user.getId(),
                    user.getUsername(),
                    StringUtils.defaultString(user.getNickname(), ""),
                    ObjectUtils.defaultIfNull(user.getAge(), 0),
                    new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(user.getCreateTime())
                },
                ","
            );
            lines.add(line);
        }
        
        // 3. 写入文件
        FileUtils.writeLines(destFile, "UTF-8", lines);
    }
    
    /**
     * 从CSV导入用户数据
     */
    public List<User> importUsersFromCsv(File csvFile) throws IOException {
        // 1. 读取文件
        List<String> lines = FileUtils.readLines(csvFile, "UTF-8");
        
        // 2. 验证数据不为空
        if (CollectionUtils.isEmpty(lines) || lines.size() < 2) {
            throw new IllegalArgumentException("CSV文件为空或格式不正确");
        }
        
        // 3. 跳过表头,解析数据
        List<User> users = new ArrayList<>();
        for (int i = 1; i < lines.size(); i++) {
            String line = lines.get(i);
            String[] fields = StringUtils.split(line, ",");
            
            if (ArrayUtils.isEmpty(fields) || fields.length < 5) {
                log.warn("跳过无效行:{}", line);
                continue;
            }
            
            User user = new User();
            user.setId(NumberUtils.toLong(fields[0]));
            user.setUsername(fields[1]);
            user.setNickname(StringUtils.defaultIfBlank(fields[2], null));
            user.setAge(NumberUtils.toInt(fields[3]));
            
            try {
                user.setCreateTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(fields[4]));
            } catch (ParseException e) {
                log.error("日期解析失败:{}", fields[4]);
                user.setCreateTime(new Date());
            }
            
            users.add(user);
        }
        
        return users;
    }
}

八、最佳实践

8.1 使用建议

1. 优先使用Commons工具类
   - 代码更简洁
   - 处理了边界情况
   - 性能经过优化

2. 注意null安全
   - StringUtils.isBlank() 比 isEmpty() 更安全
   - CollectionUtils.isEmpty() 处理了null情况
   - ObjectUtils.defaultIfNull() 提供默认值

3. 选择合适的工具类
   - 字符串操作:StringUtils
   - 集合操作:CollectionUtils
   - 文件操作:FileUtils
   - Bean操作:BeanUtils

4. 注意性能
   - 大量数据处理时使用批处理
   - 文件操作注意关闭流
   - 避免频繁的类型转换

5. 异常处理
   - BeanUtils.copyProperties() 会抛出异常
   - 文件操作需要处理IOException
   - 使用try-catch或throws声明

8.2 常见陷阱

// 陷阱1:BeanUtils.copyProperties参数顺序
// ❌ 错误:参数顺序反了
BeanUtils.copyProperties(source, target);  // 错误!

// ✓ 正确:目标对象在前
BeanUtils.copyProperties(target, source);  // 正确

// 陷阱2:StringUtils.split vs String.split
String str = "a,,b";
String[] arr1 = str.split(",");              // ["a", "", "b"]
String[] arr2 = StringUtils.split(str, ","); // ["a", "b"](忽略空字符串)

// 陷阱3:FileUtils.deleteDirectory vs File.delete
File dir = new File("testDir");
dir.delete();  // 只能删除空目录
FileUtils.deleteDirectory(dir);  // 可以删除非空目录

// 陷阱4:BeanUtils.getProperty返回String
User user = new User();
user.setAge(20);
String age = BeanUtils.getProperty(user, "age");  // "20"(String类型)
Integer ageInt = (Integer) PropertyUtils.getProperty(user, "age");  // 20(Integer类型)

九、练习题

练习1:字符串处理

/**
 * 实现一个方法,处理用户输入的手机号
 * 要求:
 * 1. 去除空格和特殊字符
 * 2. 验证是否为11位数字
 * 3. 格式化为:138****1234
 */
public String processPhoneNumber(String phone) {
    // TODO: 实现
    return null;
}

练习2:集合操作

/**
 * 实现一个方法,找出两个用户列表的共同好友
 * 要求:
 * 1. 处理null和空列表
 * 2. 返回共同好友列表
 * 3. 按用户ID排序
 */
public List<User> findCommonFriends(List<User> friends1, List<User> friends2) {
    // TODO: 实现
    return null;
}

练习3:文件操作

/**
 * 实现一个方法,批量处理图片文件
 * 要求:
 * 1. 验证文件类型(只允许jpg、png、gif)
 * 2. 计算文件MD5
 * 3. 重命名文件为:日期_MD5.扩展名
 * 4. 移动到指定目录
 */
public List<FileInfo> processImages(List<File> imageFiles, String destDir) throws IOException {
    // TODO: 实现
    return null;
}

学习检查清单

完成本文档学习后,你应该能够:

  • 理解Apache Commons的作用和价值
  • 熟练使用StringUtils进行字符串操作
  • 熟练使用CollectionUtils进行集合操作
  • 熟练使用FileUtils进行文件操作
  • 掌握BeanUtils进行对象属性复制
  • 了解DigestUtils进行加密操作
  • 了解Base64进行编码解码
  • 能够在实际项目中应用这些工具类
  • 知道常见的使用陷阱和注意事项
  • 能够选择合适的工具类解决问题

推荐资源

官方文档:

学习建议:

  1. 先掌握最常用的StringUtils和CollectionUtils
  2. 在实际项目中多使用,积累经验
  3. 遇到问题查阅官方文档
  4. 对比原生API和Commons API的区别
  5. 注意性能和边界情况处理

记住:Apache Commons是Java开发的利器,熟练掌握可以大大提高开发效率!