标准的 Java 库未能提供足够的方法来操作其核心类,Apache-commons-lang 提供了许多辅助工具,特别是字符串操作方法、基本数值方法、对象反射、并发、对象创建和序列化以及系统属性。此外,它还包含了对 java.util 的基本增强功能,日期和一系列的实用工具。
commons-lang 有两个主要版本,lang 和 lang3。lang 是早前版本,于 2002 年发布,而 lang3 是第三个大版本,摒弃了一些弱和旧的特性,不再兼容 lang,包名也更新为 lang3,现在使用主要以 lang3 为主 。
pom依赖为:
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-lang3artifactId>
<version>3.12.0version>
dependency>
下图表现了 commons-lang3 包中 Utils 类的分布
下表描述了上述 Utils 类作用及提供官方测试例子
类名 | 作用 | 官方测试例子 |
---|---|---|
AnnotationUtils | 注解相关 | AnnotationUtilsTest.java |
ArchUtils | 操作系统相关,使用System.getProperties("os.arch") 系统属性的值 | ArchUtilsTest.java |
ArrayUtils | 数组相关,提供数组添加,删除,打乱等方法 | ArrayUtilsTest.java |
BooleanUtils | boolean 相关,提供 “yes”,“no”,“off”,“on” 转换 boolean 相关方法 | BooleanUtilsTest.java |
CalendarUtils | 日历相关 | CalendarUtilsTest.java |
CharSequenceUtils | null 安全的字符序列操作方法 | CharSequenceUtilsTest.java |
CharSetUtils | 字符集合操作。提供包含,删除,压缩,计数等方法 | CharSetUtilsTest.java |
CharUtils | 字符相关 | CharUtilsTest.java |
ClassLoaderUtils | 类加载器相关 | ClassLoaderUtilsTest.java |
ClassPathUtils | ClassPath 相关 | ClassPathUtilsTest.java |
ClassUtils | 不用反射操作类,提供 Class 对象转类名 String ,类缩略名等方法 | ClassUtilsTest.java |
ComparableUtils | 提供将 Comparable.compareTo(T) 结果转换为 boolean 的辅助方法 | ComparableUtilsTest.java |
ConcurrentUtils | 并发相关 | ConcurrentUtilsTest.java |
ConstructorUtils | 反射相关,专注于构造器 | ConstructorUtilsTest.java |
DateUtils | 日期相关 | DateUtilsTest.java |
DateFormatUtils | 提供日期和时间格式化实用方法和常量 | DateFormatUtilsTest.java |
DurationFormatUtils | 提供 Duration 格式化实用方法和常量 | DurationFormatUtilsTest.java |
DurationUtils | Duration 相关 | DurationUtilsTest.java |
EnumUtils | 枚举相关 | EnumUtilsTest.java |
EventUtils | 提供了一些基于事件的实用方法 | EventUtilsTest.java |
ExceptionUtils | 异常相关,提供用于操作和检查Throwable 对象的方法 | ExceptionUtilsTest.java |
FieldUtils | 反射相关,专注于字段 | FieldUtilsTest.java |
IEEE754rUtils | 基于 IEEE-754 提供数字相关方法 | IEEE754rUtilsTest.java |
InheritanceUtils | 反射相关,主要关注于继承的实用方法 | InheritanceUtilsTest.java |
LocaleUtils | Locale 相关 | LocaleUtilsTest.java |
MethodUtils | 反射相关, 专注于方法 | MethodUtilsTest.java |
NumberUtils | 数字相关,提供检测字符串是否合法Java数字,是否可解析为数字等方法 | NumberUtilsTest.java |
ObjectUtils | 对象相关,提供对象数组判空,是否相等,最大,最小等方法 | ObjectUtilsTest.java |
RandomStringUtils | 随机字符串相关 | RandomStringUtilsTest.java |
RandomUtils | 随机数相关 | RandomUtilsTest.java |
RegExUtils | 正则相关 | RegExUtilsTest.java |
SerializationUtils | 序列化相关 | SerializationUtilsTest.java |
StringUtils | 字符串相关 | StringUtilsTest.java |
SystemUtils | java.lang.System 相关 | SystemUtilsTest.java |
ThreadUtils | 线程相关 | ThreadUtilsTest.java |
TypeUtils | 反射相关,侧重于类型检查,特别是关于泛型 | TypeUtilsTest.java |
字符串缩略
StringUtils.abbreviate("abcdefg", 6); // "abc..."
字符串 append
如果字符串尚未以任何后缀结尾,则将后缀附加到字符串的末尾
StringUtils.appendIfMissing("abcMNO", "xyz", "mno"); // "abcMNOxyz"
字符串删除末尾换行符
删除字符串末尾\r, \n 或 \r\n,只会删一次
StringUtils.chomp("abc\r\n\r\n"); // "abc\r\n"
字符串删除末尾单个字符
StringUtils.chop("abc"); // "ab"
字符串是否包含空白字符
StringUtils.containsWhitespace("hello world"); // true
字符串中字符/字符串出现次数
StringUtils.countMatches("abba", 'a'); // 2
StringUtils.countMatches("abba", "a"); // 2
字符串去除空白字符
StringUtils.deleteWhitespace(" ab c "); // "abc"
字符串差异
StringUtils.difference("abcde", "abxyz"); // "xyz"
StringUtils.difference("abcde", "xyz"); // "xyz"
字符串是否已某个后缀结束
StringUtils.endsWith("ABCDEF", "def"); // false
StringUtils.endsWithAny("abcXYZ", "def", "XYZ"); // true
StringUtils.endsWithIgnoreCase("ABCDEF", "def"); // true
字符串公共前缀
StringUtils.getCommonPrefix("abcde", "abxyz"); // "ab"
字符串是否空,null,空白字符
StringUtils.isBlank(" "); // true
StringUtils.isNotBlank(" "); // false
字符串是否空,null
StringUtils.isEmpty(""); // true
StringUtils.isEmpty(" "); // false
StringUtils.isNotEmpty(" "); // true
字符串 join
StringUtils.join(["a", "b", "c"], "--"); // "a--b--c"
字符串重复
StringUtils.repeat("ab", 2); // "abab"
字符串替换
StringUtils.replace("aba", "a", "z"); // "zbz"
字符串翻转
StringUtils.reverse("bat"); // "tab"
字符串旋转
StringUtils.rotate("abcdefg", 2); // "fgabcde"
StringUtils.rotate("abcdefg", -2); // "cdefgab"
字符串切割
StringUtils.split("abc def"); // ["abc", "def"]
StringUtils.split("abc def"); // ["abc", "def"]
StringUtils.split(" abc "); // ["abc"]
StringUtils.splitByCharacterType("ab de fg"); // ["ab", " ", "de", " ", "fg"]
StringUtils.splitByCharacterType("ab de fg"); // ["ab", " ", "de", " ", "fg"]
StringUtils.splitByCharacterType("ab:cd:ef"); // ["ab", ":", "cd", ":", "ef"]
StringUtils.splitByCharacterType("number5"); // ["number", "5"]
StringUtils.splitByCharacterType("fooBar"); // ["foo", "B", "ar"]
StringUtils.splitByCharacterType("foo200Bar"); // ["foo", "200", "B", "ar"]
StringUtils.splitByCharacterType("ASFRules"); // ["ASFR", "ules"]
字符串strip
类似 trim, trim 是删除前后空格,而 trip 删除空白字符
StringUtils.strip(" ab c "); // "ab c"
字符串截断
StringUtils.truncate("abcdefg", 4); // "abcd"
字符串包裹
StringUtils.wrap("ab", "'"); // "'ab'"
字符串是否包含字符集合字符
CharSetUtils.containsAny("hello", "k-p"); // true
CharSetUtils.containsAny("hello", "a-d"); // false
字符串包含字符集合字符计数
CharSetUtils.count("hello", "k-p"); // 3
CharSetUtils.count("hello", "a-e"); // 1
字符串删除字符集合
CharSetUtils.delete("hello", "hl"); // "eo"
字符串只保留字符集合字符
CharSetUtils.keep("hello", "hl"); // "hll"
字符串压缩字符集合字符
CharSetUtils.squeeze("hello", "k-p"); // "helo"
字符串正则删除
StringUtils.removeAll("any", Pattern.compile(".*")); // ""
StringUtils.removeAll("A<__>\n<__>B", Pattern.compile("<.*>")); // "A\nB"
StringUtils.removeAll("A<__>\n<__>B", Pattern.compile("(?s)<.*>")); // "AB"
StringUtils.removeAll("ABCabc123abc", Pattern.compile("[a-z]")); // "ABC123"
字符串正则替换
StringUtils.replaceAll("", Pattern.compile(".*"), "zzz"); // "zzz"
StringUtils.replaceAll("", Pattern.compile(".+"), "zzz"); // ""
StringUtils.replaceAll("ABCabc123", Pattern.compile("[^A-Z0-9]+"), ""); // "ABC123"
n位长度字符串
RandomStringUtils.random(10);
n位长度字符串,字符为a-zA-Z
RandomStringUtils.randomAlphabetic(10);
n位长度字符串,字符为a-zA-Z0-9
RandomStringUtils.randomAlphanumeric(10);
n位长度字符串, 字符为Ascii字符
RandomStringUtils.randomAscii(10);
n位长度字符串, 字符为数字
RandomStringUtils.randomNumeric(10);
字符串转数字
NumberUtils.toInt(""); // 0
NumberUtils.toInt("1"); // 1
NumberUtils.toFloat("1.5"); // 1.5f
NumberUtils.toDouble("1.5"); // 1.5d
NumberUtils.toLong("1"); // 1L
最大最小值
NumberUtils.max(1, 2, 3, 4); // 4
NumberUtils.min(1.0f, 2.0f, 3.0f, 4.0f); // 1.0f
分数相加减乘除
Fraction f1 = Fraction.getFraction(1, 3);
Fraction f2 = Fraction.getFraction(1, 4);
Fraction add = f1.add(f2); // 7/12
Fraction subtract = f1.subtract(f2); // 1/12
Fraction multi = f1.multiplyBy(f2); // 1/12
Fraction divide = f1.divideBy(f2); // 4/3
获取分子分母
f1.getNumerator(); // 1
f1.getDenominator(); // 3
根据字符串,double, 分子分母获取分数
Fraction.getFraction("12.3"); // 123/100
Fraction.getFraction(12.3d); // 123/100
Fraction.getFraction(123, 100); //123/100
是否相同日期
DateUtils.isSameDay(date1, date2);
是否相同时间
DateUtils.isSameInstant(date1, date2);
时间范围迭代器
// 一周以周日为起始,从 now 这周的周日生成一周
Iterator<Calendar> iterator1 = DateUtils.iterator(now, DateUtils.RANGE_WEEK_SUNDAY);
// 一周以周一为起始,从 now 这周的周一生成一周
Iterator<Calendar> iterator = DateUtils.iterator(now, DateUtils.RANGE_WEEK_MONDAY);
// 从 now 这个时间的日期作为起始生成一周
Iterator<Calendar> iterator = DateUtils.iterator(now, DateUtils.RANGE_WEEK_RELATIVE);
// 从 now 这个时间的日期作为中心生成一周
Iterator<Calendar> iterator = DateUtils.iterator(now, DateUtils.RANGE_WEEK_CENTER);
// 一周以周日为起始,从 now 这个月的第一周周日作为起始生成一个月
Iterator<Calendar> iterator = DateUtils.iterator(now, DateUtils.RANGE_MONTH_SUNDAY);
// 一周以周一为起始,从 now 这个月的第一周周一作为起始生成一个月
Iterator<Calendar> iterator = DateUtils.iterator(now, DateUtils.RANGE_MONTH_MONDAY);
解析字符串
DateUtils.parseDate(now, "yyyy-MM--dd HH:mm:ss");
日期四舍五入
SimpleDateFormat dateParser = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat dateTimeParser = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = dateParser.parse("2022-08-08");
DateUtils.round(date, Calendar.YEAR); // 2023-01-01
DateUtils.round(date, Calendar.MONTH); // 2022-08-01
Date date_half_month = dateParser.parse("2022-08-28");
DateUtils.round(date, DateUtils.SEMI_MONTH); // 2022-08-01
DateUtils.round(date_half_month, DateUtils.SEMI_MONTH); // 2022-08-16
Date date1 = dateTimeParser.parse("2022-08-08 08:08:08");
DateUtils.round(date1, Calendar.HOUR); // 2022-08-08 08:00:00
日期截断
DateUtils.truncate(date, Calendar.YEAR); // 2022-01-01
DateUtils.truncate(date, Calendar.MONTH); // 2022-08-01
DateUtils.truncate(date1, Calendar.HOUR); // 2022-08-08 08:00:00
DateFormatUtils.format(date, "yyyy-MM-dd HH:mm:ss"); // 2022-08-08 00:00:00
DateFormatUtils.ISO_8601_EXTENDED_DATE_FORMAT.format(date); // 2022-08-08
DateFormatUtils.ISO_8601_EXTENDED_DATETIME_TIME_ZONE_FORMAT.format(date); // 2022-08-08T00:00:00+08:00
DateFormatUtils.ISO_8601_EXTENDED_DATETIME_FORMAT.format(date); // 2022-08-08T00:00:00
数组增删
int [] arr = {1, 0};
ArrayUtils.add(arr, 1); // [1, 0, 1]
ArrayUtils.addFirst(arr, 1); // [1, 1, 0]
ArrayUtils.insert(1, arr, 2, 3); // [1, 2, 3, 0]
ArrayUtils.remove(arr, 1); // [1]
ArrayUtils.removeAll(arr, 0, 1); // []
int [] arr2 = {1, 0, 1, 0}
ArrayUtils.removeAllOccurrences(arr2, 1); // [0, 0]
ArrayUtils.removeElements(arr2, 1); // [0, 1, 0]
数组打乱顺序
ArrayUtils.shuffle(arr);
移位
int [] arr2 = {1, 2, 3, 4, 5};
ArrayUtils.shift(arr, 1); // [5, 1, 2, 3, 4]
ArrayUtils.shift(arr, -1); // [2, 3, 4, 5, 1]
交换
ArrayUtils.swap(arr, 0, 1); // [0, 1]
翻转
ArrayUtils.reverse(arr); // [0, 1]
随机整数
RandomUtils.nextInt(1, 100);
RandomUtils.nextInt();
RandomUtils.nextLong(1L, 1000000000L);
随机浮点数
RandomUtils.nextDouble(1.0, 1000000000.0);
RandomUtils.nextFloat(1.0f, 1000000000.0f);
随机布尔值
RandomUtils.nextBoolean();
获取环境变量
SystemUtils.getEnvironmentVariable("PATH", "default_value");
获取 Hostname
SystemUtils.getHostName();
获取 JavaHome
SystemUtils.getJavaHome();
获取 UserHome
SystemUtils.getUserHome();
获取操作系统版本
SystemUtils.OS_VERSION
获取操作系统名字
SystemUtils.OS_NAME
获取 java 版本
SystemUtils.JAVA_VERSION
获取异常信息
Throwable th = new IllegalArgumentException("Base");
ExceptionUtils.getMessage(th); // "IllegalArgumentException: Base"
获取错误的根原因
private static class ExceptionWithoutCause extends Exception {
private static final long serialVersionUID = 1L;
@SuppressWarnings("unused")
public void getTargetException() {
// noop
}
}
Throwable withoutCause = new ExceptionWithoutCause();
Throwable nested = new NestableException(withoutCause);
ExceptionUtils.getRootCause(nested);
获取栈帧消息
String[] actual = ExceptionUtils.getStackFrames(new Throwable() {
private static final long serialVersionUID = 1L;
// provide static stack trace to make test stable
@Override
public void printStackTrace(final PrintWriter s) {
s.write("org.apache.commons.lang3.exception.ExceptionUtilsTest$1\n" +
"\tat org.apache.commons.lang3.exception.ExceptionUtilsTest.testgetStackFramesGappyPath(ExceptionUtilsTest.java:706)\n" +
"\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n" +
"\tat com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)\n" +
"\tat com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)\n");
}
});
assertArrayEquals(new String[]{
"org.apache.commons.lang3.exception.ExceptionUtilsTest$1",
"\tat org.apache.commons.lang3.exception.ExceptionUtilsTest.testgetStackFramesGappyPath(ExceptionUtilsTest.java:706)",
"\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)",
"\tat com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)",
"\tat com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)"
}, actual);