Apache Commons Lang 3.21.0 常用 API 与工具类详解

详解 Apache Commons Lang 3.21.0 四大常用工具类 StringUtils、BooleanUtils、ArrayUtils、ObjectUtils,逐项实测 null 安全约定与真实返回值,含废弃 API 提示与替代写法。

Apache Commons LangApache Commons Lang2026/10/15

Apache Commons Lang 3.21.0 常用 API 与工具类详解

目标:逐一实测 Apache Commons Lang 3.21.0 最常用的四个工具类——StringUtils、BooleanUtils、ArrayUtils、ObjectUtils,用真实回显固定它们的 null 安全约定与边界行为,并标注 3.21.0 中已废弃的方法与替代写法。以下全部命令与输出均已在 Ubuntu 22.04(x86_64)实测通过。

一、环境信息

  • 操作系统:Ubuntu 22.04.5 LTS(x86_64)
  • JDK:OpenJDK 17.0.20.1
  • 构建工具:Apache Maven 3.6.3
  • 目标库:org.apache.commons:commons-lang3:3.21.0(2026-09-29 发布,零传递依赖,最低 Java 8)
  • 示例工程目录:/opt/lang-demo(安装过程见《Ubuntu 22.04 安装 Apache Commons Lang 指南》)
  • 统一运行方式:
cd /opt/lang-demo
CP=target/classes:/root/.m2/repository/org/apache/commons/commons-lang3/3.21.0/commons-lang3-3.21.0.jar
java -Dfile.encoding=UTF-8 -cp $CP demo.<DemoClass>

说明:-Dfile.encoding=UTF-8 用于规避 POSIX locale 下中文输出变问号的问题(排障实录见《Ubuntu 22.04 安装 Apache Commons Lang 指南》FAQ Q3)。本文示例类所在的实测工程共含 6 个演示类(本系列多篇文档同源),读者按本文只创建 3 个类时,编译输出的文件数不同属正常。

二、工具类总览

四个工具类的定位与包位置(均在 org.apache.commons.lang3 顶层,无需进子包):

工具类定位本文覆盖的高频方法
StringUtilsnull 安全的字符串操作全集isEmpty、isBlank、join、split、abbreviate、substringBetween、overlay、left、right、mid、capitalize、defaultString
BooleanUtilsBoolean 装箱与字符串/整数的布尔转换toBoolean、toInteger、isTrue、negate
ArrayUtils数组增删截查(int[]/String[] 等各类型重载)add、remove、subarray、isEmpty、indexOf、contains
ObjectUtils对象判空与默认值defaultIfNull(已废弃)、getIfNull、firstNonNull、allNull、anyNull

前置依赖只有一个坐标:

<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-lang3</artifactId>
  <version>3.21.0</version>
</dependency>

三、前置条件:工程与依赖确认

沿用《Ubuntu 22.04 安装 Apache Commons Lang 指南》的 Maven 工程(pom 中 commons-lang3 3.21.0 + project.build.sourceEncoding=UTF-8 + maven-compiler-plugin 3.11.0 带 -Xlint:deprecation)。先确认依赖解析正常:

cd /opt/lang-demo && mvn -B dependency:tree

输出节选(实测):

[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ lang-demo ---
[INFO] demo:lang-demo:jar:1.0.0
[INFO] \- org.apache.commons:commons-lang3:jar:3.21.0:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS

依赖树只有 commons-lang3 自身(零传递依赖)。本文新增的演示类放入 src/main/java/demo/ 后统一编译:

cd /opt/lang-demo && mvn -B compile

输出节选(实测,compile 段与结尾;仅保留与本文四类相关的 WARNING):

[INFO] Compiling 6 source files with javac [debug release 17] to target/classes
[WARNING] /opt/lang-demo/src/main/java/demo/StringUtilsDemo.java:[54,75] defaultString(java.lang.String,java.lang.String) in org.apache.commons.lang3.StringUtils has been deprecated
[WARNING] /opt/lang-demo/src/main/java/demo/ExceptionSystemDemo.java:[37,75] <T>defaultIfNull(T,T) in org.apache.commons.lang3.ObjectUtils has been deprecated
[WARNING] /opt/lang-demo/src/main/java/demo/ExceptionSystemDemo.java:[52,46] getValue() in org.apache.commons.lang3.mutable.MutableInt has been deprecated
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] Total time:  1.318 s

说明:输出末行之后还有 Finished at 与分隔线(下同,不再重复展示)。三条 WARNING 提示本文会讲到的废弃点:StringUtils.defaultString(String,String) 与 ObjectUtils.defaultIfNull 已 @Deprecated(MutableInt 属进阶篇内容,见《Apache Commons Lang 3.21.0 进阶 API 与废弃迁移详解》),功能不受影响,替代写法在对应小节给出。

四、StringUtils 详解

StringUtils 的核心设计是 null 安全:传入 null 不抛 NPE,返回确定的值。本节用一个完整演示类逐项实测,所有输出为真实回显。

4.1 判空约定:isEmpty 与 isBlank

源码 /opt/lang-demo/src/main/java/demo/StringUtilsDemo.java(完整,后续小节的方法都在这个类里):

package demo;

import java.util.Arrays;

import org.apache.commons.lang3.StringUtils;

public class StringUtilsDemo {
    public static void main(String[] args) {
        System.out.println("== null 安全约定 ==");
        System.out.println("isEmpty(null) = " + StringUtils.isEmpty(null));
        System.out.println("isEmpty(\"\") = " + StringUtils.isEmpty(""));
        System.out.println("isEmpty(\" \") = " + StringUtils.isEmpty(" "));
        System.out.println("isBlank(null) = " + StringUtils.isBlank(null));
        System.out.println("isBlank(\"\") = " + StringUtils.isBlank(""));
        System.out.println("isBlank(\" \") = " + StringUtils.isBlank(" "));
        System.out.println("isNotBlank(\" a \") = " + StringUtils.isNotBlank(" a "));

        System.out.println("== join ==");
        System.out.println("join([a,b,c], '-') = " + StringUtils.join(new String[]{"a", "b", "c"}, '-'));
        System.out.println("join([1,2,3], ',') = " + StringUtils.join(new int[]{1, 2, 3}, ','));

        System.out.println("== split ==");
        String[] parts = StringUtils.split("a,b,,c", ',');
        System.out.println("split(\"a,b,,c\", ',') = " + Arrays.toString(parts));
        System.out.println("split(null, ',') = " + Arrays.toString(StringUtils.split(null, ',')));
        System.out.println("splitPreserveAllTokens(\"a,b,,c\", ',') = " + Arrays.toString(StringUtils.splitPreserveAllTokens("a,b,,c", ',')));

        System.out.println("== abbreviate ==");
        System.out.println("abbreviate(\"abcdefg\", 10) = " + StringUtils.abbreviate("abcdefg", 10));
        System.out.println("abbreviate(\"abcdefg\", 6) = " + StringUtils.abbreviate("abcdefg", 6));
        try {
            StringUtils.abbreviate("abcdefg", 3);
        } catch (IllegalArgumentException e) {
            System.out.println("abbreviate(\"abcdefg\", 3) 抛出 IllegalArgumentException: " + e.getMessage());
        }

        System.out.println("== substringBetween ==");
        System.out.println("substringBetween(\"<a>text</a>\", \"<a>\", \"</a>\") = " + StringUtils.substringBetween("<a>text</a>", "<a>", "</a>"));

        System.out.println("== overlay ==");
        System.out.println("overlay(\"abcdef\", \"***\", 2, 5) = " + StringUtils.overlay("abcdef", "***", 2, 5));

        System.out.println("== left / right / mid ==");
        System.out.println("left(\"abcdef\", 3) = " + StringUtils.left("abcdef", 3));
        System.out.println("right(\"abcdef\", 3) = " + StringUtils.right("abcdef", 3));
        System.out.println("mid(\"abcdef\", 2, 3) = " + StringUtils.mid("abcdef", 2, 3));
        System.out.println("left(null, 3) = " + StringUtils.left(null, 3));
        System.out.println("right(\"abc\", 10) = " + StringUtils.right("abc", 10));

        System.out.println("== capitalize / defaultString ==");
        System.out.println("capitalize(\"hello\") = " + StringUtils.capitalize("hello"));
        System.out.println("capitalize(null) = " + StringUtils.capitalize(null));
        System.out.println("defaultString(null) = [" + StringUtils.defaultString(null) + "]");
        System.out.println("defaultString(null, \"N/A\") = " + StringUtils.defaultString(null, "N/A"));
    }
}

判空部分的真实回显:

== null 安全约定 ==
isEmpty(null) = true
isEmpty("") = true
isEmpty(" ") = false
isBlank(null) = true
isBlank("") = true
isBlank(" ") = true
isNotBlank(" a ") = true

要点:

  • isEmpty 只认 null 与空串,纯空格 " " 返回 false;isBlank 把纯空白也视为空。
  • null 安全:isEmpty(null)、isBlank(null) 直接返回 boolean,不抛 NPE——这正是与 str.isEmpty() 手写判空的核心差异。

4.2 拼接与拆分:join 与 split

同上类的真实回显:

== join ==
join([a,b,c], '-') = a-b-c
join([1,2,3], ',') = 1,2,3
== split ==
split("a,b,,c", ',') = [a, b, c]
split(null, ',') = null
splitPreserveAllTokens("a,b,,c", ',') = [a, b, , c]

要点:

  • join 支持 String[] 与基本类型数组(int[] 等)两类重载。
  • split 丢弃空 token:a,b,,c 只得到 3 个元素;要保留空位用 splitPreserveAllTokens(得到 4 个)。
  • split(null, ',') 返回 null 而不是抛异常。

4.3 缩写、提取与覆盖:abbreviate、substringBetween、overlay

同上类的真实回显:

== abbreviate ==
abbreviate("abcdefg", 10) = abcdefg
abbreviate("abcdefg", 6) = abc...
abbreviate("abcdefg", 3) 抛出 IllegalArgumentException: Minimum abbreviation width is 4
== substringBetween ==
substringBetween("<a>text</a>", "<a>", "</a>") = text
== overlay ==
overlay("abcdef", "***", 2, 5) = ab***f

要点:

  • abbreviate 的省略号占 3 个字符,最小可用宽度是 4,传入 3 直接抛 IllegalArgumentException(实测报错文案如上),不会被静默处理。
  • substringBetween 提取两个定界符之间的内容,取不到时返回 null。
  • overlay(start, end) 是「左闭右开」区间替换:2 到 5 的字符被 *** 替换。

4.4 取子串三件套:left、right、mid

同上类的真实回显:

== left / right / mid ==
left("abcdef", 3) = abc
right("abcdef", 3) = def
mid("abcdef", 2, 3) = cde
left(null, 3) = null
right("abc", 10) = abc

要点:

  • left/right/mid 全部 null 安全:null 进 null 出。
  • 请求长度超过串长时截到串尾(right("abc", 10) = abc),不抛异常。
  • mid(str, pos, len) 从 pos(0 起)开始取 len 个字符。

4.5 首字母大写与默认值:capitalize、defaultString

同上类的真实回显:

== capitalize / defaultString ==
capitalize("hello") = Hello
capitalize(null) = null
defaultString(null) = []
defaultString(null, "N/A") = N/A

要点:

  • capitalize 只把首字母大写,null 直接返回 null。
  • defaultString(null) 返回空串 "";defaultString(null, "N/A") 返回自定义默认值。
  • 废弃提示:双参重载 defaultString(String,String) 在 3.21.0 已 @Deprecated(4.x 编译实测见第三章 WARNING),单参重载未废弃。替代写法:不需要自定义默认值时用单参 defaultString(str),需要时用三元表达式 str == null ? "N/A" : str 或 Objects.toString(str, "N/A")。

💡 技术拓展:StringUtils 与 Guava 字符串工具的设计差异——

维度Commons StringUtilsGuava(Strings/Joiner/Splitter)
null 语义方法级 null 安全:null 进、约定值出(isEmpty(null)=true)多数方法 Preconditions 前置断言:null 直接抛 NullPointerException
空白判定isEmpty / isBlank 两档Strings.isNullOrEmpty 一档(无空白判定,需自行 trim)
拆分split(丢空 token)Splitter 链式配置(omitEmptyStrings/trimResults 可选)
拼接join(数组, 分隔符)Joiner 链式(skipNulls、useForNull 可选)
适用判断「宽容处理脏数据」的防御式风格「快速失败暴露问题」的契约式风格

选型口径:解析外部输入(日志、表单、报文)优先 StringUtils 的 null 安全;内部模块边界想尽早暴露传参 bug 用 Guava 的断言风格。两者可在同一工程共存(同 classpath 验证见《Apache Commons Lang 3.21.0 快速入门与集成示例》)。

五、BooleanUtils 详解

BooleanUtils 处理 Boolean 装箱类型与字符串/整数之间的转换,全部方法 null 安全。源码 /opt/lang-demo/src/main/java/demo/BooleanArrayDemo.java(完整,ArrayUtils 部分见第六章):

package demo;

import java.util.Arrays;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.BooleanUtils;

public class BooleanArrayDemo {
    public static void main(String[] args) {
        System.out.println("== BooleanUtils ==");
        System.out.println("toBoolean(\"yes\") = " + BooleanUtils.toBoolean("yes"));
        System.out.println("toBoolean(\"y\") = " + BooleanUtils.toBoolean("y"));
        System.out.println("toBoolean(\"on\") = " + BooleanUtils.toBoolean("on"));
        System.out.println("toBoolean(\"true\") = " + BooleanUtils.toBoolean("true"));
        System.out.println("toBoolean(\"1\") = " + BooleanUtils.toBoolean("1"));
        System.out.println("toBoolean(\"no\") = " + BooleanUtils.toBoolean("no"));
        System.out.println("toBoolean(null) = " + BooleanUtils.toBoolean((String) null));
        System.out.println("toBoolean(1) = " + BooleanUtils.toBoolean(1));
        System.out.println("toBoolean(0) = " + BooleanUtils.toBoolean(0));
        System.out.println("toInteger(true, 1, 0, -1) = " + BooleanUtils.toInteger(true, 1, 0, -1));
        System.out.println("isTrue(Boolean.TRUE) = " + BooleanUtils.isTrue(Boolean.TRUE));
        System.out.println("isTrue(null) = " + BooleanUtils.isTrue(null));
        System.out.println("negate(Boolean.TRUE) = " + BooleanUtils.negate(Boolean.TRUE));
        System.out.println("negate(null) = " + BooleanUtils.negate(null));

        System.out.println("== ArrayUtils ==");
        int[] arr = {1, 2, 3};
        int[] added = ArrayUtils.add(arr, 4);
        System.out.println("add([1,2,3], 4) = " + Arrays.toString(added));
        System.out.println("remove([1,2,3,4], 1) = " + Arrays.toString(ArrayUtils.remove(added, 1)));
        System.out.println("subarray([1,2,3,4], 1, 3) = " + Arrays.toString(ArrayUtils.subarray(added, 1, 3)));
        System.out.println("isEmpty(new int[0]) = " + ArrayUtils.isEmpty(new int[0]));
        System.out.println("isEmpty(null) = " + ArrayUtils.isEmpty((int[]) null));
        int[] dup = {1, 2, 3, 2};
        System.out.println("indexOf([1,2,3,2], 2) = " + ArrayUtils.indexOf(dup, 2));
        System.out.println("indexOf([1,2,3,2], 2, 2) = " + ArrayUtils.indexOf(dup, 2, 2));
        System.out.println("indexOf([1,2,3], 9) = " + ArrayUtils.indexOf(arr, 9));
        System.out.println("contains([1,2,3], 2) = " + ArrayUtils.contains(arr, 2));
        System.out.println("add(null, \"x\") = " + Arrays.toString(ArrayUtils.add((String[]) null, "x")));
    }
}

5.1 字符串与整数转布尔:toBoolean

运行整类的真实回显(本节先看 BooleanUtils 段):

== BooleanUtils ==
toBoolean("yes") = true
toBoolean("y") = true
toBoolean("on") = true
toBoolean("true") = true
toBoolean("1") = true
toBoolean("no") = false
toBoolean(null) = false
toBoolean(1) = true
toBoolean(0) = false

要点:

  • 字符串重载接受 "true"/"on"/"yes"/"y"(忽略大小写),实测 "1" 也返回 true——解析配置文件时容易踩到的非直觉点。
  • "no"、null、未知字符串一律返回 false,不抛异常;需要区分「非法值」时不要用这个重载。
  • 整数重载按非零判断:toBoolean(1) = true、toBoolean(0) = false。

5.2 整数映射、判真与取反:toInteger、isTrue、negate

同上类的真实回显:

toInteger(true, 1, 0, -1) = 1
isTrue(Boolean.TRUE) = true
isTrue(null) = false
negate(Boolean.TRUE) = false
negate(null) = null

要点:

  • toInteger(bool, trueValue, falseValue, nullValue) 把三种状态映射为三个整数,避免手写 if-else。
  • isTrue(null) 返回 false 而非 NPE;同理还有 isFalse/isNotTrue 系列。
  • negate 对 null 返回 null(三值逻辑),对 TRUE/FALSE 正常取反。

六、ArrayUtils 详解

ArrayUtils 补齐了 JDK 数组的增删截查能力。注意:数组长度不可变,add/remove 返回的是新数组。

6.1 增删截:add、remove、subarray

源码见 5.1 的 BooleanArrayDemo.java(ArrayUtils 段),真实回显:

== ArrayUtils ==
add([1,2,3], 4) = [1, 2, 3, 4]
remove([1,2,3,4], 1) = [1, 3, 4]
subarray([1,2,3,4], 1, 3) = [2, 3]

要点:

  • add 追加元素产生新数组;remove(index) 按下标删除(下标 1 是第二个元素)。
  • subarray(begin, end) 左闭右开,与 Arrays.copyOfRange 语义一致,但对下标越界更宽容(自动截边界)。

6.2 判空与查找:isEmpty、indexOf、contains

同上类的真实回显:

isEmpty(new int[0]) = true
isEmpty(null) = true
indexOf([1,2,3,2], 2) = 1
indexOf([1,2,3,2], 2, 2) = 3
indexOf([1,2,3], 9) = -1
contains([1,2,3], 2) = true
add(null, "x") = [x]

要点:

  • isEmpty 对空数组与 null 都返回 true。
  • indexOf 支持从指定下标开始找(fromIndex=2 时找到第二个 2 的位置 3);找不到返回 -1。
  • 对 null 数组 add 会自动新建数组:add(null, "x") = [x],省掉一处判空。

七、ObjectUtils 详解

ObjectUtils 处理对象级判空与默认值兜底。源码 /opt/lang-demo/src/main/java/demo/ExceptionSystemDemo.java(完整源码与 ExceptionUtils/SystemUtils 部分见《Apache Commons Lang 3.21.0 进阶 API 与废弃迁移详解》,本节截取 ObjectUtils 段):

package demo;

import org.apache.commons.lang3.JavaVersion;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.SystemUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.lang3.mutable.MutableInt;
import org.apache.commons.lang3.time.DurationFormatUtils;

public class ExceptionSystemDemo {
    public static void main(String[] args) {
        System.out.println("== ObjectUtils ==");
        System.out.println("defaultIfNull(null, \"dft\") = " + ObjectUtils.defaultIfNull(null, "dft"));
        System.out.println("firstNonNull(null, \"x\") = " + ObjectUtils.firstNonNull(null, "x"));
        System.out.println("firstNonNull(null, null) = " + ObjectUtils.firstNonNull(null, null));
        System.out.println("allNull(null, null) = " + ObjectUtils.allNull(null, null));
        System.out.println("allNull(null, \"a\") = " + ObjectUtils.allNull(null, "a"));
        System.out.println("anyNull(\"a\", null) = " + ObjectUtils.anyNull("a", null));
        System.out.println("anyNull(\"a\", \"b\") = " + ObjectUtils.anyNull("a", "b"));
    }
}

说明:实际源码还包含 ExceptionUtils、SystemUtils、MutableInt、DurationFormatUtils 段(进阶篇内容),为聚焦本节仅展示 ObjectUtils 段;运行输出取其对应片段,命令与全文运行完全一致。

运行真实回显(ObjectUtils 段):

== ObjectUtils ==
defaultIfNull(null, "dft") = dft
firstNonNull(null, "x") = x
firstNonNull(null, null) = null
allNull(null, null) = true
allNull(null, "a") = false
anyNull("a", null) = true
anyNull("a", "b") = false

要点:

  • firstNonNull 返回第一个非 null 参数,全 null 时返回 null。
  • allNull/anyNull 是多参数判空的直接表达,省掉链式 ||。

7.1 废弃提示与替代写法(实测)

defaultIfNull(T,T) 在 3.21.0 已 @Deprecated(第三章编译 WARNING 实录),但功能正常。替代方法是 getIfNull(obj, default),实测编译无任何告警(验证类 DepCheck.java,放在 /opt/lang-jars):

import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.mutable.MutableInt;

public class DepCheck {
    public static void main(String[] args) {
        System.out.println("getIfNull(null, \"dft\") = " + ObjectUtils.getIfNull((String) null, "dft"));
        System.out.println("getIfNull(null, supplier) = " + ObjectUtils.getIfNull((String) null, () -> "dft-supp"));
        MutableInt mi = new MutableInt(3);
        System.out.println("mi.intValue() = " + mi.intValue());
        System.out.println("mi.incrementAndGet() = " + mi.incrementAndGet());
    }
}

编译并运行(-Xlint:deprecation 全量检查,无告警输出):

cd /opt/lang-jars
javac -Xlint:deprecation -encoding UTF-8 -cp /root/.m2/repository/org/apache/commons/commons-lang3/3.21.0/commons-lang3-3.21.0.jar -d . DepCheck.java
java -Dfile.encoding=UTF-8 -cp .:/root/.m2/repository/org/apache/commons/commons-lang3/3.21.0/commons-lang3-3.21.0.jar DepCheck

输出(实测):

getIfNull(null, "dft") = dft
getIfNull(null, supplier) = dft-supp
mi.intValue() = 3
mi.incrementAndGet() = 4

要点:

  • getIfNull(obj, default) 与 getIfNull(obj, Supplier) 两个重载在 3.21.0 均未废弃,直接作为 defaultIfNull 的替代;Supplier 版可延迟构造默认值。
  • 迁移成本为零:ObjectUtils.defaultIfNull(a, b) 逐字替换为 ObjectUtils.getIfNull(a, b)。

八、注意事项

  1. null 安全不是「无约定」:每个方法对 null 的返回值是固定的(isEmpty→true、split→null、left→null 等),写代码前按本文实测口径对齐,避免「以为返回 null 结果是 true」之类的误判。
  2. 数组方法返回新数组:ArrayUtils.add/remove/subarray 都不改原数组,必须接住返回值(5.1 源码中 int[] added = ArrayUtils.add(arr, 4) 的写法)。
  3. 废弃 API 清单:本文涉及的 StringUtils.defaultString(String,String)、ObjectUtils.defaultIfNull 已 @Deprecated;连同 Range/MutableInt/Random 系的完整废弃清单与逐项迁移写法,统一见《Apache Commons Lang 3.21.0 进阶 API 与废弃迁移详解》第十一章总表。
  4. BooleanUtils 字符串重载不抛异常:未知串返回 false,解析强校验场景请自行前置正则或用 toBooleanObject(可区分第三态)。
  5. 编码:编译期 project.build.sourceEncoding=UTF-8、运行期 -Dfile.encoding=UTF-8,两者独立配置(实录见《Ubuntu 22.04 安装 Apache Commons Lang 指南》第七章与 FAQ)。

九、常见问题(FAQ)

Q1:StringUtils 传 null 会抛 NPE 吗?

不会。这是该类与手写 str.isEmpty() 先判空的差异所在,实测口径:isEmpty(null)=true、isBlank(null)=true、split(null, ',')=null、left(null, 3)=null、capitalize(null)=null(4.1~4.5 各段真实回显)。只有 abbreviate 的宽度非法等「参数非法」场景才抛 IllegalArgumentException(4.3 实测)。

Q2:defaultString(null, "N/A") 编译出现 deprecated 告警怎么办?

3.21.0 只废弃了双参重载,单参 defaultString(String) 未废弃。替代写法三选一:改用单参版本;用三元表达式 str == null ? "N/A" : str;用 JDK 自带 Objects.toString(str, "N/A")。功能完全等价(4.5 实测双参返回 N/A)。

Q3:BooleanUtils.toBoolean("1") 为什么返回 true?

字符串重载的真值集合是 "true"/"on"/"yes"/"y"(忽略大小写),3.21.0 中 "1" 也在真值集合里(5.1 实测 toBoolean("1") = true)。反直觉点在于:整数重载 toBoolean(1) 也为 true,但两者语义不同——字符串版是「集合匹配」,整数版是「非零即真」。若希望把 "1" 视为非法输入,需前置校验。

Q4:split 结果和 JDK 的 String.split 不一样?

不一样且差异有两处:一是 Commons 的 split 丢弃全部空 token(a,b,,c 得 3 个),JDK 版保留中间空 token 只丢弃尾部;二是 Commons 对 null 输入返回 null,JDK 版抛 NPE。需要保留空位时用 splitPreserveAllTokens(4.2 实测两者输出对比)。

Q5:ObjectUtils.defaultIfNull 还能用吗?

能,功能正常(第七章实测返回 dft),只是 3.21.0 标记了 @Deprecated。新代码直接用 getIfNull(7.1 实测无告警),存量代码可在升级时批量替换,行为无差异。

十、参考链接

  1. StringUtils 官方 Javadoc(3.21.0):https://commons.apache.org/proper/commons-lang/javadocs/api-release/org/apache/commons/lang3/StringUtils.html
  2. BooleanUtils 官方 Javadoc:https://commons.apache.org/proper/commons-lang/javadocs/api-release/org/apache/commons/lang3/BooleanUtils.html
  3. ArrayUtils 官方 Javadoc:https://commons.apache.org/proper/commons-lang/javadocs/api-release/org/apache/commons/lang3/ArrayUtils.html
  4. ObjectUtils 官方 Javadoc:https://commons.apache.org/proper/commons-lang/javadocs/api-release/org/apache/commons/lang3/ObjectUtils.html
  5. 环境搭建与依赖引入:《Ubuntu 22.04 安装 Apache Commons Lang 指南》
  6. 进阶工具类与废弃迁移:《Apache Commons Lang 3.21.0 进阶 API 与废弃迁移详解》