求求你了昏翰,不要再自己實現這些邏輯了筑舅,java開源工具類不香嗎?
下文主要分享這幾個方向的常用工具類:
字符串相關工具類
Java 中 String 應該是日常用的最多一個類吧,平常我們很多代碼需要圍繞 String 尚揣,做一些處理。
JDK 提供 String API 雖然比較多掖举,但是功能比較基礎惑艇,通常我們需要結合 String 多個方法才能完成一個業(yè)務功能。
下面介紹一下 Apache 提供的一個工具類 StringUtils.
Maven Pom 信息如下:
? ? org.apache.commons? ? commons-lang3? ? 3.10復制代碼
commons-lang 有兩個版本,一個是 commons-lang3 滨巴,一個是 commons-lang 思灌。
commons-lang 是老版本,已經很久沒有維護了恭取。
commons-lang3 是一直在維護的版本泰偿,推薦直接使用這個版本。
注意:如果你系統(tǒng)已經有 commons-lang蜈垮,注意如果直接替換成 commons-lang3耗跛,將會編譯錯誤。commons-lang3 中相關類與 commons-lang 一樣攒发,但是包名不一樣调塌。
判斷字符串是否為空
判斷字符串是否為空,想必每個人應該都寫過吧:
if(null == str || str.isEmpty()) {}復制代碼
雖然這段代碼非常簡單惠猿,但是說實話羔砾,阿粉以前還是在這里犯過空指針的異常的。
使用 StringUtils 偶妖,上面代碼可以替換下面這樣:
if(StringUtils.isEmpty(str)) {}復制代碼
StringUtils 內部還有一個方法 isBlank姜凄,也是用來判斷字符串是否為空,兩個方法比較相近趾访,比較搞混态秧,主要區(qū)別如下:
// 字符串固定長度 8位,若不足扼鞋,往左補 0StringUtils.leftPad("test", 8,"0");復制代碼
判斷字符串是否為空申鱼,使用頻率非常高,這里大家可以使用 IDEA Prefix 的功能云头,輸入直接生成判空語句润讥。
字符串固定長度
這個通常用于字符串需要固定長度的場景,比如需要固定長度字符串作為流水號盘寡,若流水號長度不足楚殿,,左邊補 0 竿痰。
這里當然可以使用 String#format 方法脆粥,不過阿粉覺得比較麻煩,這里可以這樣使用:
//?字符串固定長度 8位影涉,若不足变隔,往左補?0StringUtils.leftPad("test",?8,"0");復制代碼
另外還有一個 StringUtils#rightPad,這個方法與上面方法正好相反。
字符串關鍵字替換
StringUtils 提供一些列的方法蟹倾,可以替換某些關鍵字:
// 默認替換所有關鍵字StringUtils.replace("aba","a","z")? ="zbz";// 替換關鍵字匣缘,僅替換一次StringUtils.replaceOnce("aba","a","z")? ="zba";// 使用正則表達式替換StringUtils.replacePattern("ABCabc123","[^A-Z0-9]+","")? ="ABC123"猖闪;....復制代碼
字符串拼接
字符串拼接是個常見的需求,簡單辦法使用 StringBuilder 循環(huán)遍歷拼接:
String[] array = new String[]{"test","1234","5678"};StringBuilder stringBuilder = new StringBuilder();for(String s : array) {? ? stringBuilder.append(s).append(";");}// 防止最終拼接字符串為空if(stringBuilder.length() > 0) {? ? stringBuilder.deleteCharAt(stringBuilder.length() - 1);}System.out.println(stringBuilder.toString());復制代碼
上面業(yè)務代碼不太難肌厨,但是需要注意一下上面這段代碼非常容易出錯培慌,容易拋出 StringIndexOutOfBoundsException。
這里我們可以直接使用以下方法獲取拼接之后字符串:
StringUtils.join(["a","b","c"],",")????="a,b,c"復制代碼
StringUtils 只能傳入數組拼接字符串柑爸,不過我比較喜歡集合拼接吵护,所以再推薦下 Guava 的 Joiner。
實例代碼如下:
String[] array = new String[]{"test","1234","5678"};List list=new ArrayList<>();list.add("test");list.add("1234");list.add("5678");StringUtils.join(array,",");// 逗號分隔符表鳍,跳過 nullJoiner joiner=Joiner.on(",").skipNulls();joiner.join(array);joiner.join(list);復制代碼
字符串拆分
有字符串拼接馅而,就會有拆分字符串的需求,同樣的 StringUtils 也有拆分字符串的方法譬圣。
StringUtils.split("a..b.c",'.')? = ["a","b","c"]StringUtils.splitByWholeSeparatorPreserveAllTokens("a..b.c",".")= ["a","","b","c"]復制代碼
ps:注意以上兩個方法區(qū)別瓮恭。
StringUtils 拆分之后得到是一個數組,我們可以使用 Guava 的
Splitter splitter = Splitter.on(",");// 返回是一個 List 集合厘熟,結果:[ab, , b, c]splitter.splitToList("ab,,b,c");// 忽略空字符串屯蹦,輸出結果 [ab, b, c]splitter.omitEmptyStrings().splitToList("ab,,b,c")復制代碼
StringUtils 內部還有其他常用的方法,小伙伴可以自行查看其 API盯漂。
日期相關工具類
DateUtils/DateFormatUtils
JDK8 之前,Java 只提供一個 Date 類笨农,平常我們需要將 Date 按照一定格式轉化成字符串就缆,我們需要使用 SimpleDateFormat。
SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// Date 轉 字符串simpleDateFormat.format(new Date());// 字符串 轉 DatesimpleDateFormat.parse("2020-05-07 22:00:00");復制代碼
代碼雖然簡單谒亦,但是這里需要注意 SimpleDateFormat竭宰,不是線程安全的,多線程環(huán)境一定要注意使用安全份招。
這里阿粉推薦commons-lang3下的時間工具類DateUtils/DateFormatUtils,解決 Date 與字符串轉化問題切揭。
ps:吐槽一下,你們工程中有沒有多個叫 DateUtils 類锁摔?阿粉發(fā)現我們現有工程廓旬,多個模塊有提供這個類,每個實現大同小異谐腰。
使用方法非常簡單:
// Date 轉化為字符串DateFormatUtils.format(new Date(),"yyyy-MM-dd HH:mm:ss");// 字符串 轉 DateDateUtils.parseDate("2020-05-07 22:00:00","yyyy-MM-dd HH:mm:ss");復制代碼
除了格式轉化之外孕豹,DateUtils 還提供時間計算的相關功能。
Date now = new Date();// Date 加 1 天Date addDays = DateUtils.addDays(now, 1);// Date 加 33 分鐘Date addMinutes = DateUtils.addMinutes(now, 33);// Date 減去 233 秒Date addSeconds = DateUtils.addSeconds(now, -233);// 判斷是否 Wie 同一天boolean sameDay = DateUtils.isSameDay(addDays, addMinutes);// 過濾時分秒,若 now 為 2020-05-07 22:13:00 調用 truncate 方法以后// 返回時間為 2020-05-07 00:00:00Date truncate = DateUtils.truncate(now, Calendar.DATE);復制代碼
JDK8 時間類
JDK8 之后十气,Java 將日期與時間分為 LocalDate励背,LocalTime,功能定義更加清晰砸西,當然其也提供一個 LocalDateTime叶眉,包含日期與時間址儒。這些類相對于 Date 類優(yōu)點在于,這些類與 String 類一樣都是不變類型衅疙,不但線程安全莲趣,而且不能修改。
ps:仔細對比 mysql 時間日期類型 DATE炼蛤,TIME妖爷,DATETIME,有沒有感覺差不多
現在 mybatis 等 ORM 框架已經支持 LocalDate 與 JDBC 時間類型轉化理朋,所以大家可以直接將時間字段實際類型定義為 JDK8 時間類型絮识,然后再進行相關轉化。
如果依然使用的是 Date 類型嗽上,如果需要使用新的時間類型次舌,我們需要進行相關轉化。兩者之間進行轉化兽愤, 稍微復雜一點彼念,我們需要顯示指定當前時區(qū)。
Date now = new Date();// Date-----> LocalDateTime 這里指定使用當前系統(tǒng)默認時區(qū)LocalDateTimelocalDateTime = now.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();// LocalDateTime------> Date 這里指定使用當前系統(tǒng)默認時區(qū)Date date = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());復制代碼
接下來我們使用 LocalDateTime 進行字符串格式化浅萧。
// 按照 yyyy-MM-dd HH:mm:ss 轉化時間LocalDateTime dateTime = LocalDateTime.parse("2020-05-07 22:34:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));// 將 LocalDateTime 格式化字符串String format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(dateTime);復制代碼
另外我們使用 LocalDateTime 獲取當前時間年份咬清,月份特別簡單:
LocalDateTime now = LocalDateTime.now();// 年int year = now.getYear();// 月int month = now.getMonthValue();// 日int day = now.getDayOfMonth();復制代碼
最后我們還可以使用 LocalDateTime 進行日期加減,獲取下一天的時間:
LocalDateTime now = LocalDateTime.now();// 當前時間加一天LocalDateTime plusDays = now.plusDays(1l);// 當前時間減一個小時LocalDateTime minusHours = now.minusHours(1l);// 還有很多其他方法復制代碼
總之 JDK8 提供的時間類非常好用民逼,還沒用過小伙伴霍殴,可以嘗試下。
集合/數組相關
集合與數組我們日常也需要經常使用帝簇,也需要對其進行判空:
if(null == list || list.isEmpty()) {}復制代碼
ps: 數組徘郭、Map 集合與其類似
上面代碼如字符串判空一樣寫起來都非常簡單,但是也比較容易寫出會拋出空指針異常的代碼丧肴。這里我們可以使用commons-collections提供工具類残揉。
pom 信息:
? ? org.apache.commons? ? commons-collections4? ? 4.4復制代碼
ps: 還有一個低版本的 ,artifactId 為 commons-collections
我們可以使用 CollectionUtils/MapUtils進行判空判斷芋浮。
// List/Set 集合判空if(CollectionUtils.isEmpty(list)){}// Map 等集合進行判空if(MapUtils.isEmpty(map)) {? ? }復制代碼
至于數組判空判斷需要使用 commons-lang 下的 ArrayUtils進行判斷:
// 數組判空if(ArrayUtils.isEmpty(array)) {? ? }復制代碼
除此之外還有一些列的對于集合增強方法抱环,比如快速將數組加入到現有集合中:
List listA = new ArrayList<>();listA.add("1");listA.add("2");listA.add("3");String[] arrays = new String[]{"a","b","c"};CollectionUtils.addAll(listA, arrays);復制代碼
其他方法感興趣同學可以再自行研究下,另外 Guava 中也有提供對于集合的操作增強類 Lists/Maps,這個可以看下阿粉之前寫的:老司機阿粉帶你玩轉 Guava 集合類纸巷。
I/O 相關
JDK 有提供一系列的類可以讀取文件等江醇,不過阿粉覺得那些類有些晦澀難懂,實現一個小功能可能還要寫好多代碼何暇,而且還不一定能寫對陶夜。
阿粉推薦一下 Apache 提供的 commons-io 庫,增強 I/O 操作裆站,簡化操作難度条辟。pom 信息:
? ? commons-io? ? commons-io? ? 2.6復制代碼
FileUtils-文件操作工具類
文件操作工具類提供一系列方法黔夭,可以讓我們快速讀取寫入文件。
快速實現文件/文件夾拷貝操作 ,FileUtils.copyDirectory/FileUtils.copyFile
// 拷貝文件File fileA = new File("E:\\test\\test.txt");File fileB = new File("E:\\test1\\test.txt");FileUtils.copyFile(fileA,fileB);復制代碼
使用 FileUtils.listFiles 獲取指定文件夾上所有文件
// 按照指定文件后綴如java,txt等去查找指定文件夾的文件File directory = new File("E:\\test");FileUtils.listFiles(directory, new String[]{"txt"},false);復制代碼
使用 FileUtils.readLines 讀取該文件所有行羽嫡。
// 讀取指定文件所有行 不需要使用while循環(huán)讀取流了List lines = FileUtils.readLines(fileA)復制代碼
有讀就存在寫本姥,可以使用 FileUtils.writeLines,直接將集合中數據杭棵,一行行寫入文本婚惫。
// 可以一行行寫入文本List lines = new ArrayList<>();.....FileUtils.writeLines(lines)復制代碼
IOUtils-I/O 操作相關工具類
FileUtils 主要針對相關文件操作,IOUtils 更加針對底層 I/O,可以快速讀取 InputStream魂爪。實際上 FileUtils 底層操作依賴就是 IOUtils先舷。
IOUtils可以適用于一個比較試用的場景,比如支付場景下滓侍,HTTP 異步通知場景蒋川。如果我們使用 JDK 原生方法寫:
從 Servlet 獲取異步通知內容
byte[] b = null;ByteArrayOutputStream baos = null;String respMsg = null;try {? ? byte[] buffer = new byte[1024];? ? baos = new ByteArrayOutputStream();? // 獲取輸入流? ? InputStreamin= request.getInputStream();for(int len = 0; (len = in.read(buffer)) > 0; ) {? ? ? ? baos.write(buffer, 0, len);? ? }? ? b = baos.toByteArray();? ? baos.close();? // 字節(jié)數組轉化成字符串? ? String reqMessage = new String(b,"utf-8");} catch (IOException e) {? } finally {if(baos != null) {? ? ? ? try {? ? ? ? ? ? baos.close();? ? ? ? } catch (IOException e) {? ? ? ? ? ? ? ? ? }? ? }}復制代碼
上面代碼說起來還是挺復雜的。不過我們使用 IOUtils撩笆,一個方法就可以簡單搞定:
// 將輸入流信息全部輸出到字節(jié)數組中byte[] b = IOUtils.toByteArray(request.getInputStream());// 將輸入流信息轉化為字符串String resMsg = IOUtils.toString(request.getInputStream());復制代碼
ps: InputStream 不能被重復讀取
計時
編程中有時需要統(tǒng)計代碼的的執(zhí)行耗時捺球,當然執(zhí)行代碼非常簡單,結束時間與開始時間相減即可夕冲。
long start = System.currentTimeMillis();? //獲取開始時間//其他代碼//...long end = System.currentTimeMillis(); //獲取結束時間System.out.println("程序運行時間: "+ (end - start) +"ms");復制代碼
雖然代碼很簡單氮兵,但是非常不靈活,默認情況我們只能獲取 ms 單位歹鱼,如果需要轉換為秒泣栈,分鐘,就需要另外再計算醉冤。
這里我們介紹 Guava Stopwatch 計時工具類秩霍,借助他統(tǒng)計程序執(zhí)行時間篙悯,使用方式非常靈活蚁阳。
commons-lang3 與 Spring-core 也有這個工具類,使用方式大同小異鸽照,大家根據情況選擇螺捐。
// 創(chuàng)建之后立刻計時,若想主動開始計時Stopwatch stopwatch = Stopwatch.createStarted();// 創(chuàng)建計時器矮燎,但是需要主動調用 start 方法開始計時// Stopwatch stopwatch = Stopwatch.createUnstarted();// stopWatch.start();// 模擬其他代碼耗時TimeUnit.SECONDS.sleep(2l);// 當前已經消耗的時間System.out.println(stopwatch.elapsed(TimeUnit.SECONDS));;TimeUnit.SECONDS.sleep(2l);// 停止計時 未開始的計時器調用 stop 將會拋錯 IllegalStateExceptionstopwatch.stop();// 再次統(tǒng)計總耗時System.out.println(stopwatch.elapsed(TimeUnit.SECONDS));;// 重新開始定血,將會在原來時間基礎計算,若想重新從 0開始計算诞外,需要調用 stopwatch.reset()stopwatch.start();TimeUnit.SECONDS.sleep(2l);System.out.println(stopwatch.elapsed(TimeUnit.SECONDS));復制代碼
輸出結果為:
246復制代碼
總結
今天介紹了字符串澜沟、日期、數組/集合峡谊、I/O茫虽、計時等工具類刊苍,簡化日常業(yè)務代碼。大家看完可以嘗試一下濒析,不得不說正什,這些工具類真香!
作者:java夢想口服液
鏈接:https://juejin.cn/post/6844904151759978510
來源:掘金
著作權歸作者所有号杏。商業(yè)轉載請聯系作者獲得授權婴氮,非商業(yè)轉載請注明出處。