程序員的福音 - Apache Commons Lang

程序猿的福音 - Apache Commons簡介

Apache Commons Lang是對java.lang的擴(kuò)展负蠕,基本上是commons中最常用的工具包成艘。

目前Lang包有兩個(gè)commons-lang3和commons-lang列敲。

lang最新版本是2.6糙捺,最低要求Java1.2以上咐扭,目前官方已不在維護(hù)例证。lang3目前最新版本是3.12.0懊渡,最低要求Java8以上膛薛。相對于lang來說完全支持Java8的特性听隐,廢除了一些舊的API。該版本無法兼容舊有版本哄啄,于是為了避免沖突改名為lang3雅任。

Java8以上的用戶推薦使用lang3代替lang风范,下面我們主要以lang3 - 3.12.0版本為例做說明。

以下為整體包結(jié)構(gòu):

org.apache.commons.lang3
org.apache.commons.lang3.builder
org.apache.commons.lang3.concurrent
org.apache.commons.lang3.event
org.apache.commons.lang3.exception
org.apache.commons.lang3.math
org.apache.commons.lang3.mutable
org.apache.commons.lang3.reflect
org.apache.commons.lang3.text
org.apache.commons.lang3.text.translate
org.apache.commons.lang3.time
org.apache.commons.lang3.tuple
圖片

下面只列舉其中常用的加以說明沪么,其余感興趣的可以自行翻閱源碼研究乌企。

01. 日期相關(guān)

在Java8之前,日期只提供了java.util.Date類和java.util.Calendar類成玫,說實(shí)話這些API并不是很好用加酵,而且也存在線程安全的問題,所以Java8推出了新的日期API哭当。如果你還在用舊的日期API猪腕,可以使用DateUtils和DateFormatUtils工具類。

1. 字符串轉(zhuǎn)日期

final String strDate = "2021-07-04 11:11:11";
final String pattern = "yyyy-MM-dd HH:mm:ss";
// 原生寫法
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
Date date1 = sdf.parse(strDate);
// commons寫法
Date date2 = DateUtils.parseDate(strDate, pattern);

2. 日期轉(zhuǎn)字符串

final Date date = new Date();
final String pattern = "yyyy年MM月dd日";
// 原生寫法
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
String strDate = sdf.format(date);
// 使用commons寫法
String strDate = DateFormatUtils.format(date, pattern);

3. 日期計(jì)算

final Date date = new Date();
// 原生寫法
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.add(Calendar.DATE, 5); // 加5天
cal.add(Calendar.HOUR_OF_DAY, -5); // 減5小時(shí)
// 使用commons寫法
Date newDate1 = DateUtils.addDays(date, 5); // 加5天
Date newDate2 = DateUtils.addHours(date, -5); // 減5小時(shí)
Date newDate3 = DateUtils.truncate(date, Calendar.DATE); // 過濾時(shí)分秒
boolean isSameDay = DateUtils.isSameDay(newDate1, newDate2); // 判斷是否是同一天

02. 字符串相關(guān)

字符串是Java中最常用的類型钦勘,相關(guān)的工具類也可以說是最常用的陋葡,下面直接看例子

1. 字符串判空

String str = "";
// 原生寫法
if (str == null || str.length() == 0) {
    // Do something
}
// commons寫法
if (StringUtils.isEmpty(str)) {
    // Do something
}  
/* StringUtils.isEmpty(null)      = true
 * StringUtils.isEmpty("")        = true
 * StringUtils.isEmpty(" ")       = false
 * StringUtils.isEmpty("bob")     = false
 * StringUtils.isEmpty("  bob  ") = false
 */

相關(guān)方法:

// isEmpty取反
StringUtils.isNotEmpty(str);
/* 
 * null, 空串,空格為true
 * StringUtils.isBlank(null)      = true
 * StringUtils.isBlank("")        = true
 * StringUtils.isBlank(" ")       = true
 * StringUtils.isBlank("bob")     = false
 * StringUtils.isBlank("  bob  ") = false
 */
StringUtils.isBlank(str);
// isBlank取反
StringUtils.isNotBlank(str);
// 任意一個(gè)參數(shù)為空則結(jié)果為true
StringUtils.isAnyEmpty(str1, str2, str3);
// 所有參數(shù)為空則結(jié)果為true
StringUtils.isAllEmpty(str1, str2, str3);

2. 字符串去空格

// 去除兩端空格彻采,不需要判斷null
String newStr = StringUtils.trim(str);
/*
 * 去除兩端空格腐缤,如果是null則轉(zhuǎn)換為空字符串
 * StringUtils.trimToEmpty(null)          = ""
 * StringUtils.trimToEmpty("")            = ""
 * StringUtils.trimToEmpty("     ")       = ""
 * StringUtils.trimToEmpty("abc")         = "abc"
 * StringUtils.trimToEmpty("    abc    ") = "abc"
 */
newStr = StringUtils.trimToEmpty(str);
/*
 * 去除兩端空格,如果結(jié)果是空串則轉(zhuǎn)換為null
 * StringUtils.trimToNull(null)          = null
 * StringUtils.trimToNull("")            = null
 * StringUtils.trimToNull("     ")       = null
 * StringUtils.trimToNull("abc")         = "abc"
 * StringUtils.trimToNull("    abc    ") = "abc"
 */
newStr = StringUtils.trimToNull(str);
/*
 * 去兩端 給定字符串中任意字符
 * StringUtils.strip(null, *)          = null
 * StringUtils.strip("", *)            = ""
 * StringUtils.strip("abc", null)      = "abc"
 * StringUtils.strip("  abc", null)    = "abc"
 * StringUtils.strip("abc  ", null)    = "abc"
 * StringUtils.strip(" abc ", null)    = "abc"
 * StringUtils.strip("  abcyx", "xyz") = "  abc"
 */
newStr = StringUtils.strip(str, "stripChars");
// 去左端 給定字符串中任意字符
newStr = StringUtils.stripStart(str, "stripChars");
// 去右端 給定字符串中任意字符
newStr = StringUtils.stripEnd(str, "stripChars");

3. 字符串分割

/*
 * 按照空格分割字符串 結(jié)果為數(shù)組
 * StringUtils.split(null)       = null
 * StringUtils.split("")         = []
 * StringUtils.split("abc def")  = ["abc", "def"]
 * StringUtils.split("abc  def") = ["abc", "def"]
 * tringUtils.split(" abc ")    = ["abc"]
 */
 StringUtils.split(str);
 // 按照某些字符分割 結(jié)果為數(shù)組肛响,自動(dòng)去除了截取后的空字符串
 StringUtils.split(str, ",");

4. 取子字符串

// 獲得"ab.cc.txt"中最后一個(gè).之前的字符串
StringUtils.substringBeforeLast("ab.cc.txt", "."); // ab.cc
// 相似方法
// 獲得"ab.cc.txt"中最后一個(gè).之后的字符串(常用于獲取文件后綴名)
StringUtils.substringAfterLast("ab.cc.txt", "."); // txt
// 獲得"ab.cc.txt"中第一個(gè).之前的字符串
StringUtils.substringBefore("ab.cc.txt", "."); // ab
// 獲得"ab.cc.txt"中第一個(gè).之后的字符串
StringUtils.substringAfter("ab.cc.txt", "."); // cc.txt
// 獲取"ab.cc.txt"中.之間的字符串
StringUtils.substringBetween("ab.cc.txt", "."); // cc
// 看名字和參數(shù)應(yīng)該就知道干什么的了
StringUtils.substringBetween("a(bb)c", "(", ")"); // bb

5. 其他

// 首字母大寫
StringUtils.capitalize("test"); // Test
// 字符串合并
StringUtils.join(new int[]{1,2,3}, ",");// 1,2,3
// 縮寫
StringUtils.abbreviate("abcdefg", 6);// "abc..."
// 判斷字符串是否是數(shù)字
StringUtils.isNumeric("abc123");// false
// 刪除指定字符
StringUtils.remove("abbc", "b"); // ac
// ... ... 還有很多岭粤,感興趣可以自己研究

6. 隨機(jī)字符串

// 隨機(jī)生成長度為5的字符串
RandomStringUtils.random(5);
// 隨機(jī)生成長度為5的"只含大小寫字母"字符串
RandomStringUtils.randomAlphabetic(5);
// 隨機(jī)生成長度為5的"只含大小寫字母和數(shù)字"字符串
RandomStringUtils.randomAlphanumeric(5);
// 隨機(jī)生成長度為5的"只含數(shù)字"字符串
RandomStringUtils.randomNumeric(5);

03. 反射相關(guān)

反射是Java中非要重要的特性,原生的反射API代碼冗長特笋,Lang包中反射相關(guān)的工具類可以很方便的實(shí)現(xiàn)反向相關(guān)功能剃浇,下面看例子

1. 屬性操作

public class ReflectDemo {
    private static String sAbc = "111";
    private String abc = "123";
    public void fieldDemo() throws Exception {
        ReflectDemo reflectDemo = new ReflectDemo();
        // 反射獲取對象實(shí)例屬性的值
        // 原生寫法
        Field abcField = reflectDemo.getClass().getDeclaredField("abc");
        abcField.setAccessible(true);// 設(shè)置訪問級別,如果private屬性不設(shè)置則訪問會(huì)報(bào)錯(cuò)
        String value = (String) abcField.get(reflectDemo);// 123
        // commons寫法
        String value2 = (String) FieldUtils.readDeclaredField(reflectDemo, "abc", true);//123
        // 方法名如果不含Declared會(huì)向父類上一直查找
    }
}

注:方法名含Declared的只會(huì)在當(dāng)前類實(shí)例上尋找猎物,不包含Declared的在當(dāng)前類上找不到則會(huì)遞歸向父類上一直查找虎囚。

相關(guān)方法:

public class ReflectDemo {
    private static String sAbc = "111";
    private String abc = "123";
    public void fieldRelated() throws Exception {
        ReflectDemo reflectDemo = new ReflectDemo();
        // 反射獲取對象屬性的值
        String value2 = (String) FieldUtils.readField(reflectDemo, "abc", true);//123
        // 反射獲取類靜態(tài)屬性的值
        String value3 = (String) FieldUtils.readStaticField(ReflectDemo.class, "sAbc", true);//111
        // 反射設(shè)置對象屬性值
        FieldUtils.writeField(reflectDemo, "abc", "newValue", true);
        // 反射設(shè)置類靜態(tài)屬性的值
        FieldUtils.writeStaticField(ReflectDemo.class, "sAbc", "newStaticValue", true);
    }
}

2. 獲取注解方法

// 獲取被Test注解標(biāo)識(shí)的方法
        
// 原生寫法
List<Method> annotatedMethods = new ArrayList<Method>();
for (Method method : ReflectDemo.class.getMethods()) {
    if (method.getAnnotation(Test.class) != null) {
        annotatedMethods.add(method);
    }
}
// commons寫法
Method[] methods = MethodUtils.getMethodsWithAnnotation(ReflectDemo.class, Test.class);

3. 方法調(diào)用

private static void testStaticMethod(String param1) {}
private void testMethod(String param1) {}
  
public void invokeDemo() throws Exception {
    // 調(diào)用函數(shù)"testMethod"
    ReflectDemo reflectDemo = new ReflectDemo();
    // 原生寫法
    Method testMethod = reflectDemo.getClass().getDeclaredMethod("testMethod");
    testMethod.setAccessible(true); // 設(shè)置訪問級別,如果private函數(shù)不設(shè)置則調(diào)用會(huì)報(bào)錯(cuò)
    testMethod.invoke(reflectDemo, "testParam");
    // commons寫法
    MethodUtils.invokeExactMethod(reflectDemo, "testMethod", "testParam");
    
    // ---------- 類似方法 ----------
    // 調(diào)用static方法
    MethodUtils.invokeExactStaticMethod(ReflectDemo.class, "testStaticMethod", "testParam");
    // 調(diào)用方法(含繼承過來的方法)
    MethodUtils.invokeMethod(reflectDemo, "testMethod", "testParam");
    // 調(diào)用static方法(當(dāng)前不存在則向父類尋找匹配的靜態(tài)方法)
    MethodUtils.invokeStaticMethod(ReflectDemo.class, "testStaticMethod", "testParam");
}

其他還有ClassUtils蔫磨,ConstructorUtils淘讥,TypeUtils等不是很常用,有需求的可以現(xiàn)翻看類的源碼堤如。

04. 系統(tǒng)相關(guān)

主要是獲取操作系統(tǒng)和JVM一些信息蒲列,下面看例子

// 判斷操作系統(tǒng)類型
boolean isWin = SystemUtils.IS_OS_WINDOWS;
boolean isWin10 = SystemUtils.IS_OS_WINDOWS_10;
boolean isWin2012 = SystemUtils.IS_OS_WINDOWS_2012;
boolean isMac = SystemUtils.IS_OS_MAC;
boolean isLinux = SystemUtils.IS_OS_LINUX;
boolean isUnix = SystemUtils.IS_OS_UNIX;
boolean isSolaris = SystemUtils.IS_OS_SOLARIS;
// ... ...

// 判斷java版本
boolean isJava6 = SystemUtils.IS_JAVA_1_6;
boolean isJava8 = SystemUtils.IS_JAVA_1_8;
boolean isJava11 = SystemUtils.IS_JAVA_11;
boolean isJava14 = SystemUtils.IS_JAVA_14;
// ... ...

// 獲取java相關(guān)目錄
File javaHome = SystemUtils.getJavaHome();
File userHome = SystemUtils.getUserHome();// 操作系統(tǒng)用戶目錄
File userDir = SystemUtils.getUserDir();// 項(xiàng)目所在路徑
File tmpDir = SystemUtils.getJavaIoTmpDir();

05. 總結(jié)

除了以上介紹的工具類外,還有其他不是很常用的就不多做介紹了煤惩。感興趣的可以自行翻閱源碼研究嫉嘀。
后續(xù)章節(jié)我將繼續(xù)給大家介紹commons中其他好用的工具類庫,期待你的關(guān)注魄揉。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末剪侮,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌瓣俯,老刑警劉巖杰标,帶你破解...
    沈念sama閱讀 222,681評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異彩匕,居然都是意外死亡腔剂,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評論 3 399
  • 文/潘曉璐 我一進(jìn)店門驼仪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來掸犬,“玉大人,你說我怎么就攤上這事绪爸⊥逅椋” “怎么了?”我有些...
    開封第一講書人閱讀 169,421評論 0 362
  • 文/不壞的土叔 我叫張陵奠货,是天一觀的道長介褥。 經(jīng)常有香客問我,道長递惋,這世上最難降的妖魔是什么柔滔? 我笑而不...
    開封第一講書人閱讀 60,114評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮萍虽,結(jié)果婚禮上睛廊,老公的妹妹穿的比我還像新娘。我一直安慰自己贩挣,他們只是感情好喉前,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,116評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著王财,像睡著了一般。 火紅的嫁衣襯著肌膚如雪裕便。 梳的紋絲不亂的頭發(fā)上绒净,一...
    開封第一講書人閱讀 52,713評論 1 312
  • 那天,我揣著相機(jī)與錄音偿衰,去河邊找鬼挂疆。 笑死,一個(gè)胖子當(dāng)著我的面吹牛下翎,可吹牛的內(nèi)容都是我干的缤言。 我是一名探鬼主播,決...
    沈念sama閱讀 41,170評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼视事,長吁一口氣:“原來是場噩夢啊……” “哼胆萧!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,116評論 0 277
  • 序言:老撾萬榮一對情侶失蹤跌穗,失蹤者是張志新(化名)和其女友劉穎订晌,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蚌吸,經(jīng)...
    沈念sama閱讀 46,651評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡锈拨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,714評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了羹唠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片奕枢。...
    茶點(diǎn)故事閱讀 40,865評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖佩微,靈堂內(nèi)的尸體忽然破棺而出验辞,到底是詐尸還是另有隱情,我是刑警寧澤喊衫,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布跌造,位于F島的核電站,受9級特大地震影響族购,放射性物質(zhì)發(fā)生泄漏壳贪。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,211評論 3 336
  • 文/蒙蒙 一寝杖、第九天 我趴在偏房一處隱蔽的房頂上張望违施。 院中可真熱鬧,春花似錦瑟幕、人聲如沸磕蒲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,699評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽辣往。三九已至,卻和暖如春殖卑,著一層夾襖步出監(jiān)牢的瞬間站削,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,814評論 1 274
  • 我被黑心中介騙來泰國打工孵稽, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留许起,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,299評論 3 379
  • 正文 我出身青樓菩鲜,卻偏偏與公主長得像园细,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子接校,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,870評論 2 361

推薦閱讀更多精彩內(nèi)容