commons-lang3(Java 基础语言增强)
6、时间与性能
commons-lang3 提供了多个专门用于时间处理、高精度性能耗时统计以及线程安全的日期格式化工具。它们不仅能大幅简化代码,还能解决 Java 原生 SimpleDateFormat 线程不安全的问题。
在项目中直接引入标准 commons-lang3 依赖即可使用上述所有工具:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.14.0</version>
</dependency>
6.1、StopWatch(耗时统计与性能秒表)
在评估代码性能、统计方法执行耗时或记录多阶段(分段)执行耗时(Lap/Split)时,StopWatch 提供了极其便捷且语义清晰的秒表功能,无需手写多个 System.currentTimeMillis() 相减。
6.1.1、核心API
- 状态控制
createStarted():快捷创建并立即启动秒表(静态工厂方法)。start() / stop():启动 / 停止秒表。suspend() / resume():暂停秒表 / 恢复计时。reset():重置秒表状态以备复用。
- 分段与标记
split():标记一个分段点(可通过 getSplitTime() 获取从起点到该标记点的耗时)。unsplit():清除分段标记。
- 读取时间
getTime(TimeUnit timeUnit):以指定时间单位(如毫秒、微秒、秒)获取当前耗时。formatTime():获取格式化的耗时字符串(格式如 00:00:01.234)。
6.1.2、使用示例
import org.apache.commons.lang3.time.StopWatch;
import java.util.concurrent.TimeUnit;
public class StopWatchDemo {
public static void main(String[] args) throws InterruptedException {
// 1. 创建并自动启动秒表
StopWatch watch = StopWatch.createStarted();
// 阶段一执行
Thread.sleep(200);
watch.split(); // 标记分段点 1
System.out.println("阶段一耗时: " + watch.getSplitTime() + " ms");
// 阶段二执行
Thread.sleep(300);
watch.unsplit(); // 解除分段
// 暂停与恢复示例
watch.suspend(); // 暂停计时
// 此处的耗时不会计入秒表
Thread.sleep(100);
watch.resume(); // 恢复计时
watch.stop(); // 停止秒表
// 2. 读取总耗时
System.out.println("总计耗时(毫秒): " + watch.getTime());
System.out.println("总计耗时(秒): " + watch.getTime(TimeUnit.SECONDS));
System.out.println("格式化耗时输出: " + watch.formatTime()); // 00:00:00.5xx
}
}
阶段一耗时: 201 ms
总计耗时(毫秒): 505
总计耗时(秒): 0
格式化耗时输出: 00:00:00.505
6.2、FastDateFormat(线程安全的日期格式化)
原生的 java.text.SimpleDateFormat 是线程不安全的,在多线程高并发环境下(如 Spring 单例 Service 中)直接复用会导致格式化异常。FastDateFormat 是 SimpleDateFormat 的高效、线程安全替代品。
6.2.1、核心API
getInstance(String pattern):获取指定模式的格式化实例(内部自动缓存,全局复用)。getDateTimeInstance(int dateStyle, int timeStyle):按标准样式(如 DateFormat.FULL、SHORT)获取日期时间格式化器。format(Date date) / format(long millis) / format(Calendar calendar):格式化日期对象/时间戳为字符串。parse(String source):将字符串线程安全地解析为 Date 对象。
6.2.2、使用示例
import org.apache.commons.lang3.time.FastDateFormat;
import java.text.ParseException;
import java.util.Date;
public class FastDateFormatDemo {
// 线程安全的全局单例格式化对象,可在多线程环境安全共享
private static final FastDateFormat DATE_FORMAT =
FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss");
public static void main(String[] args) throws ParseException {
// 1. 格式化 Date 与时间戳
String nowStr = DATE_FORMAT.format(new Date());
String millisStr = DATE_FORMAT.format(System.currentTimeMillis());
System.out.println("当前时间: " + nowStr);
// 2. 解析字符串为 Date
Date date = DATE_FORMAT.parse("2026-09-04 15:30:00");
System.out.println("解析得到的 Date: " + date);
}
}
当前时间: 2026-09-04 15:39:46
解析得到的 Date: Fri Sep 04 15:30:00 CST 2026
6.3、DateUtils(日期安全计算与裁切)
针对传统 java.util.Date 和 Calendar 的日期加减、对齐取整、区间比较提供了大量便利方法。
6.3.1、核心API
- 日期加减
addDays(Date date, int amount) / addHours / addMonths / addYears:对日期指定单位进行增加或减少(传负数即为减)。
- 日期裁切与对齐(Truncate / Ceiling / Round)
truncate(Date date, int field):向下裁切(例如裁切到 Calendar.DAY_OF_MONTH 即可获取当天的 00:00:00)。ceiling(Date date, int field):向上对齐(例如向上对齐到 Calendar.DAY_OF_MONTH 即可获取当天的 23:59:59.999 的下一毫秒)。
- 判定与比较
isSameDay(Date date1, Date date2):忽略时分秒,仅判断两 Date 是否属于同一天。isSameInstant(Date date1, Date date2):比较两 Date 是否代表同一个绝对时间戳。
6.3.2、使用示例
import org.apache.commons.lang3.time.DateUtils;
import java.util.Calendar;
import java.util.Date;
public class DateUtilsDemo {
public static void main(String[] args) {
Date now = new Date();
// 1. 日期加减计算
Date nextWeek = DateUtils.addDays(now, 7);
Date previousHour = DateUtils.addHours(now, -1);
// 2. 获取当天的起点时刻 (00:00:00.000)
Date startOfDay = DateUtils.truncate(now, Calendar.DAY_OF_MONTH);
System.out.println("今天起点时刻: " + startOfDay);
// 3. 判断是否为同一天
boolean sameDay = DateUtils.isSameDay(now, nextWeek); // false
System.out.println("是否同一天: " + sameDay);
}
}
今天起点时刻: Fri Sep 04 00:00:00 CST 2026
是否同一天: false
6.4、DurationFormatUtils(时间段与时长格式化)
专门用于将两个时间点之间的时间差(时长/Duration)格式化为人类易读的文本(如:3天 5小时 12分钟),常用于生成监控报告、耗时任务展示等。
6.4.1、核心API
formatDuration(long durationMillis, String format):将毫秒数值格式化为指定文本(如 “HH:mm:ss.SSS”)。formatDurationWords(long durationMillis, boolean suppressLeadingZeroElements, boolean suppressTrailingZeroElements):将毫秒数转换为英文单词时间描述(如 “3 days 2 hours”)。formatPeriod(long startMillis, long endMillis, String format):计算两时间点之间的差值并格式化(精确支持月/年差异)。
6.4.2、使用示例
import org.apache.commons.lang3.time.DurationFormatUtils;
public class DurationFormatDemo {
public static void main(String[] args) {
long durationMillis = 185425000L; // 约 51 小时 30 分钟 25 秒
// 1. 自定义格式输出 (HH:mm:ss)
String formatted = DurationFormatUtils.formatDuration(durationMillis, "HH:mm:ss");
System.out.println("格式化时长: " + formatted); // "51:30:25"
// 2. 支持天数与时间的结合 (d天 HH小时 mm分)
String daysFormatted = DurationFormatUtils.formatDuration(durationMillis, "d'天' HH'小时' mm'分钟'");
System.out.println("天数格式化: " + daysFormatted); // "2天 03小时 30分钟"
// 3. 英文文本自动描述
String words = DurationFormatUtils.formatDurationWords(durationMillis, true, true);
System.out.println("单词描述: " + words); // "2 days 3 hours 30 minutes"
}
}
格式化时长: 51:30:25
天数格式化: 2天 03小时 30分钟
单词描述: 2 days 3 hours 30 minutes 25 seconds
7、反射与对象元数据
commons-lang3 提供了多个专门简化 Java 反射(Reflection)与对象元数据(Metadata)提取的工具类。原生的 Java 反射代码往往冗长、繁琐且必须处理大量受检异常(如 IllegalAccessException、NoSuchFieldException),而 commons-lang3 通过强悍的封装,实现了免去受检异常捕获、自动破除私有访问限制(Auto-Override Access)以及支持父类递归查找。
如果在项目中使用上述反射与元数据工具,添加以下 Maven 依赖即可:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.14.0</version>
</dependency>
7.1、FieldUtils(属性与字段操作)
FieldUtils 专注于对类或对象的字段(Field)进行读取与写入,自动绕过私有访问控制(自动调用 setAccessible(true)),并支持向上递归读取父类继承的私有字段。
7.1.1、核心API
- 读取字段(Read)
readField(Object target, String fieldName, boolean forceAccess):从对象实例中读取指定字段的值(forceAccess=true 可直接读取私有字段)。readDeclaredField(Object target, String fieldName, boolean forceAccess):仅读取目标对象类中显式声明的字段(不含父类)。readStaticField(Class<?> cls, String fieldName, boolean forceAccess):安全读取类的静态属性(Static Field)。
- 写入字段(Write)
writeField(Object target, String fieldName, Object value, boolean forceAccess):向对象的指定字段写入值。writeStaticField(Class<?> cls, String fieldName, Object value, boolean forceAccess):向类的静态属性写入值。
- 获取字段元数据
getAllFieldsList(Class<?> cls):获取指定类及其所有超类(Superclasses)中声明的所有 Field 集合。getDeclaredField(Class<?> cls, String fieldName, boolean forceAccess):获取字段的元数据 Field 对象。
7.1.2、使用示例
import org.apache.commons.lang3.reflect.FieldUtils;
import java.util.List;
import java.lang.reflect.Field;
public class FieldUtilsDemo {
// 模拟测试实体类
static class Parent {
private String parentSecret = "Parent Value";
}
static class Child extends Parent {
private Integer id = 101;
private static String SYSTEM_CODE = "SYS_01";
}
public static void main(String[] args) throws IllegalAccessException {
Child child = new Child();
// 1. 递归读取父类的私有属性 (无视 private)
String parentVal = (String) FieldUtils.readField(child, "parentSecret", true);
System.out.println("父类私有属性: " + parentVal); // "Parent Value"
// 2. 修改子类的私有属性
FieldUtils.writeField(child, "id", 202, true);
System.out.println("修改后的 id: " + FieldUtils.readField(child, "id", true)); // 202
// 3. 读取与修改静态属性
String code = (String) FieldUtils.readStaticField(Child.class, "SYSTEM_CODE", true);
FieldUtils.writeStaticField(Child.class, "SYSTEM_CODE", "SYS_02", true);
// 4. 获取当前类及所有父类的所有字段定义
List<Field> allFields = FieldUtils.getAllFieldsList(Child.class);
System.out.println("总字段数(含父类): " + allFields.size()); // 包含 id, SYSTEM_CODE, parentSecret 等
}
}
父类私有属性: Parent Value
修改后的 id: 202
总字段数(含父类): 3
7.2、MethodUtils(方法调用与反射)
MethodUtils 简化了通过反射查找并执行方法的过程,支持自动匹配最佳重载方法(Overloaded Methods)以及执行私有方法。
7.2.1、核心API
- 普通方法执行
invokeMethod(Object object, String methodName, Object... args):匹配最佳参数签名并执行对象方法。invokeExactMethod(Object object, String methodName, Object... args):严格按照参数类型完全一致匹配并执行。invokeMethod(Object object, boolean forceAccess, String methodName, Object... args):突破访问限制执行私有(private)或受保护的(protected)方法。
- 静态方法执行
invokeStaticMethod(Class<?> cls, String methodName, Object... args):执行类的静态方法。
- 查找元数据
getMatchingMethod(Class<?> cls, String methodName, Class<?>... parameterTypes):根据方法名和参数类型自动匹配并返回最兼容的 Method 对象。
7.2.2、使用示例
import org.apache.commons.lang3.reflect.MethodUtils;
public class MethodUtilsDemo {
static class Service {
private String secretCalculate(int base, double multiplier) {
return "Result: " + (base * multiplier);
}
public void printInfo(Number num) {
System.out.println("Number: " + num);
}
}
public static void main(String[] args) throws Exception {
Service service = new Service();
// 1. 强制执行对象的私有方法 (带参数)
String res = (String) MethodUtils.invokeMethod(service, true, "secretCalculate", 10, 1.5);
System.out.println(res); // "Result: 15.0"
// 2. 智能重载匹配(自动将 Integer 转换为 Number 匹配 printInfo)
MethodUtils.invokeMethod(service, "printInfo", 100); // 自动匹配到 printInfo(Number)
}
}
7.3、ConstructorUtils(构造函数与实例化)
基于反射动态创建对象实例时,原生的 Class.newInstance() 存在诸多限制(如无法处理有参构造方法)。ConstructorUtils 专门用于优雅地解决动态构造对象的问题。
7.3.1、核心API
invokeConstructor(Class<T> cls, Object... args):自动根据传入参数挑选最匹配的构造方法并创建实例。invokeExactConstructor(Class<T> cls, Object... args):精确匹配构造方法参数并创建实例。getMatchingAccessibleConstructor(Class<T> cls, Class<?>... parameterTypes):查找可访问的兼容构造函数。
7.3.2、使用示例
import org.apache.commons.lang3.reflect.ConstructorUtils;
public class ConstructorUtilsDemo {
static class User {
private String name;
private Integer age;
public User(String name, Number age) { // 注意参数是 Number 类型
this.name = name;
this.age = age.intValue();
}
}
public static void main(String[] args) throws Exception {
// 自动匹配 User(String, Number) 构造函数并创建实例(传参 25 为 Integer,自动向下兼容)
User user = ConstructorUtils.invokeConstructor(User.class, "Bob", 25);
System.out.println("成功创建对象: " + user.name + ", " + user.age);
}
}
7.4、TypeUtils(泛型与类型元数据分析)
Java 的泛型存在类型擦除(Type Erasure)机制,直接解析极为复杂。TypeUtils 提供了对 Type、ParameterizedType、GenericArrayType 等复杂泛型元数据的类型判定、赋值推导与替换。
7.4.1、核心API
isAssignable(Type type, Type toType):判断某个类型是否可以安全赋值给另一个类型(完美支持泛型擦除后的泛型嵌套类型判断)。getTypeArguments(Type type, Class<?> toClass):提取类或接口继承树中指定的泛型参数映射关系(如获取 List<String> 中的 String 类型)。getRawType(Type type, Type assigningType):从泛型类型中提取原始类型 Class<?>。
7.4.2、使用示例
import org.apache.commons.lang3.reflect.TypeUtils;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
public class TypeUtilsDemo {
static class StringListContainer implements List<String> {
// 模拟实现了 List<String> 的类
// ... 此处省略接口未实现方法
}
public static void main(String[] args) {
// 1. 检查类型兼容性 (泛型赋值判定)
boolean assignable = TypeUtils.isAssignable(
StringListContainer.class,
TypeUtils.parameterize(List.class, String.class)
);
System.out.println("是否兼容 List<String>: " + assignable); // true
// 2. 提取具体实现的泛型类型参数
Map<TypeVariable<?>, Type> typeArgs = TypeUtils.getTypeArguments(StringListContainer.class, Iterable.class);
System.out.println("Iterable 泛型实参: " + typeArgs.values()); // [class java.lang.String]
}
}
7.5、ClassUtils(类信息元数据工具)
提供比原生 java.lang.Class 更丰富的元数据获取工具,主要用于类名简写获取、包名提取、接口递归获取与基本类型映射。
7.5.1、核心API
- 包与类名提取
getShortClassName(Class<?> cls) / getShortClassName(String className):获取去除包名后的类名(例如 String)。getPackageName(Class<?> cls):获取类所在的包名。getAbbreviatedName(Class<?> cls, int len):获取缩写包名的类全称(例如将 com.example.service.UserService 缩写为 c.e.s.UserService)。
- 接口与父类查找
getAllInterfaces(Class<?> cls):递归获取目标类及其所有超类实现的所有接口。getAllSuperclasses(Class<?> cls):获取目标类的所有父类列表。
- 包装类型与基本类型转换
primitiveToWrapper(Class<?> cls) / wrapperToPrimitive:基本数据类型与包装类型 Class 对象的相互转换。
7.5.2、使用示例
import org.apache.commons.lang3.ClassUtils;
import java.util.ArrayList;
import java.util.List;
public class ClassUtilsDemo {
public static void main(String[] args) {
// 1. 包名与类名缩写
System.out.println(ClassUtils.getShortClassName(ArrayList.class)); // "ArrayList"
System.out.println(ClassUtils.getPackageName(ArrayList.class)); // "java.util"
System.out.println(ClassUtils.getAbbreviatedName(ArrayList.class, 10)); // "j.u.ArrayList"
// 2. 递归获取实现的所有接口
List<Class<?>> interfaces = ClassUtils.getAllInterfaces(ArrayList.class);
System.out.println("ArrayList 实现的接口数: " + interfaces.size());
// 包含 List, Collection, Iterable, RandomAccess, Cloneable, Serializable 等
// 3. 基本类型与包装类型 Class 转换
Class<?> wrapper = ClassUtils.primitiveToWrapper(int.class); // Integer.class
System.out.println("int 对应的包装类: " + wrapper.getSimpleName()); // "Integer"
}
}
ArrayList
java.util
j.u.ArrayList
ArrayList 实现的接口数: 6
int 对应的包装类: Integer
8、系统与环境
commons-lang3 提供了多个专门用于获取操作系统信息、JVM 运行环境、硬件 CPU 架构以及线程上下文的工具类。它们封装了底层的 System.getProperty()、Runtime 以及操作系统探测逻辑,提供了空安全、语义清晰的常量与 API,极大地简化了跨平台开发和环境适配。
在项目中直接引入标准的 commons-lang3 依赖即可使用上述所有工具:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.14.0</version>
</dependency>
8.1、SystemUtils(系统与 JVM 环境工具核心)
SystemUtils 是获取操作系统和 Java 运行环境信息最常用的类。它内部预定义了大量的静态布尔常量和属性常量,避免了手写 System.getProperty(“…”) 时拼写错误或因属性不存在而产生的 null 隐患。
8.1.1、核心API
- 操作系统判定常量(boolean)
IS_OS_WINDOWS / IS_OS_MAC / IS_OS_LINUX / IS_OS_UNIX:快速判断当前应用程序运行在什么操作系统上。IS_OS_WINDOWS_10 / IS_OS_MAC_OSX:精确判断具体的操作系统版本。
- JDK / JVM 环境判定
IS_JAVA_17 / IS_JAVA_21:判断当前运行的 JDK 版本。isJavaVersionAtLeast(JavaVersion requiredVersion):判断当前 Java 版本是否大于或等于指定版本(支持传入 JavaVersion.JAVA_17 等枚举)。isJavaVersionAtMost(JavaVersion requiredVersion):判断当前 Java 版本是否小于或等于指定版本。
- 系统路径与环境常量(安全 File 或 String)
getUserHome() / USER_HOME:获取当前操作系统的用户主目录(如 /Users/username 或 C:\Users\username)。getJavaIoTmpDir() / JAVA_IO_TMPDIR:获取系统临时文件目录。getJavaHome() / JAVA_HOME:获取当前 JRE/JDK 的安装目录。FILE_ENCODING / USER_TIMEZONE:获取当前默认的文件编码与时区。
8.1.2、使用示例
import org.apache.commons.lang3.JavaVersion;
import org.apache.commons.lang3.SystemUtils;
import java.io.File;
public class SystemUtilsDemo {
public static void main(String[] args) {
// 1. 跨平台操作系统条件分支判断
if (SystemUtils.IS_OS_WINDOWS) {
System.out.println("当前运行在 Windows 环境");
} else if (SystemUtils.IS_OS_LINUX) {
System.out.println("当前运行在 Linux 环境");
} else if (SystemUtils.IS_OS_MAC) {
System.out.println("当前运行在 macOS 环境");
}
// 2. JDK 版本特性前置校验
if (SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_17)) {
System.out.println("当前 JDK >= 17,允许使用 Record / Text Block 等新特性");
}
// 3. 安全获取系统关键目录与配置
File userHome = SystemUtils.getUserHome();
File tempDir = SystemUtils.getJavaIoTmpDir();
System.out.println("用户主目录: " + userHome.getAbsolutePath());
System.out.println("临时文件目录: " + tempDir.getAbsolutePath());
System.out.println("当前系统编码: " + SystemUtils.FILE_ENCODING);
}
}
8.2、ArchUtils(硬件 CPU 架构工具)
ArchUtils 专门用于探测当前服务器或客户端机器的 CPU 硬件架构(如 x86、x86_64、ARM、PPC 等)以及系统的位数(32位 或 64位)。非常适合用于在 JNI 本地库加载(加载 .so / .dll)、性能调优或特定硬件指令集匹配的场景。
8.2.1、核心API
getProcessor():获取当前机器的 Processor 硬件处理器对象。Processor对象方法与枚举processor.getArch():获取 CPU 位数类型,返回 Processor.Arch.BIT_32 或 Processor.Arch.BIT_64。processor.getType():获取 CPU 架构大类,返回 Processor.Type 枚举(如 X86、IA_64、PPC 等)。processor.is32Bit() / is64Bit():判断系统是否为 32 位或 64 位。processor.isX86() / isIA64() / isPPC():判断当前 CPU 是否属于某种特定架构。
8.2.2、使用示例
import org.apache.commons.lang3.ArchUtils;
import org.apache.commons.lang3.arch.Processor;
public class ArchUtilsDemo {
public static void main(String[] args) {
// 1. 获取当前 CPU 处理器信息
Processor processor = ArchUtils.getProcessor();
// 2. 读取位数与架构
System.out.println("CPU 架构类型: " + processor.getType()); // 如 X86
System.out.println("是否为 64 位架构: " + processor.is64Bit());
// 3. 典型应用场景:根据 CPU 架构加载不同的 JNI 本地动态库 (.so/.dll)
String libName;
if (processor.isX86() && processor.is64Bit()) {
libName = "native_lib_x86_64.so";
} else if (processor.is32Bit()) {
libName = "native_lib_x86_32.so";
} else {
libName = "native_lib_generic.so";
}
System.out.println("拟加载的底层 C++ 库: " + libName);
}
}
CPU 架构类型: X86
是否为 64 位架构: true
拟加载的底层 C++ 库: native_lib_x86_64.so
8.3、ThreadUtils(线程环境与上下文工具)
ThreadUtils 提供了对当前 JVM 运行线程与线程组(ThreadGroup)的层级遍历、条件查找与诊断支持。比原生 Thread 类提供了更高阶的线程安全搜索方法。
8.3.1、核心API
- 查找线程
findThreadById(long threadId):通过线程 ID 查找对应的 Thread 对象。findThreadsByName(String threadName):通过线程名称查找所有同名线程。findThreads(ThreadPredicate predicate):根据自定义谓词条件过滤并查找符合条件的线程。
- 查找线程组
getAllThreadGroups():获取当前 JVM 中的所有线程组(ThreadGroup)。getAllThreads():获取当前 JVM 中运行的所有线程集合。
8.3.2、使用示例
import org.apache.commons.lang3.ThreadUtils;
import java.util.Collection;
public class ThreadUtilsDemo {
public static void main(String[] args) {
// 1. 获取当前 JVM 中所有的活跃线程
Collection<Thread> allThreads = ThreadUtils.getAllThreads();
System.out.println("当前活跃线程总数: " + allThreads.size());
// 2. 按名称精确查找线程
Collection<Thread> mainThreads = ThreadUtils.findThreadsByName("main");
for (Thread t : mainThreads) {
System.out.println("找到主线程 ID: " + t.getId() + ", 状态: " + t.getState());
}
// 3. 使用条件过滤器查找(例如:查找所有名字包含 "pool" 且处于 RUNNABLE 状态的线程)
Collection<Thread> poolThreads = ThreadUtils.findThreads(thread ->
thread.getName().contains("pool") && thread.getState() == Thread.State.RUNNABLE
);
System.out.println("符合条件的线程池线程数: " + poolThreads.size());
}
}
8.4、LocaleUtils(多语言与区域设置工具)
在国际化(i18n)系统开发中,系统常常需要根据环境或用户传入的字符串动态加载 Locale。原生的 Locale 构造方法不具备容错性,而 LocaleUtils 提供了安全解析、有效性验证以及查找备用语言列表的工具。
8.4.1、核心API
toLocale(String str):将形如 “zh_CN”、“en_US”、“fr” 的字符串安全解析为 Locale 对象(格式合法性严格校验)。availableLocaleList() / availableLocaleSet():获取当前 JVM 允许并支持的所有 Locale 列表。isAvailableLocale(Locale locale):验证某个 Locale 是否被当前系统所支持。lookup(Locale locale):根据当前传入的 Locale 自动推导回退查找顺序(如 “zh_CN” 的回退链为 zh_CN -> zh -> 默认 Locale)。
8.4.2、使用示例
import org.apache.commons.lang3.LocaleUtils;
import java.util.List;
import java.util.Locale;
public class LocaleUtilsDemo {
public static void main(String[] args) {
// 1. 将字符串转为 Locale 对象
Locale zhCN = LocaleUtils.toLocale("zh_CN");
System.out.println("语言: " + zhCN.getLanguage() + ", 国家/地区: " + zhCN.getCountry());
// 2. 验证 Locale 是否被系统支持
boolean isSupported = LocaleUtils.isAvailableLocale(zhCN);
System.out.println("zh_CN 是否受支持: " + isSupported); // true
// 3. 获取区域回退链(常用于国际化资源文件 fallback 查找)
List<Locale> localeLookupList = LocaleUtils.localeLookupList(Locale.TAIWAN);
// 输出顺序: zh_TW -> zh -> 系统默认 Locale
System.out.println("语言回退优先级: " + localeLookupList);
}
}
(二)&spm=1001.2101.3001.5002&articleId=164368196&d=1&t=3&u=291219776fb2495dbaf6b88c65ec2e81)
494

被折叠的 条评论
为什么被折叠?



