通用工具類(字符串、時間格式化、BeanUtils、IO)
1. commons-lang3庫
1.1. org.apache.commons.lang3.StringUtils類
日常代碼中,我們經常和String字符串打交道,經常對字符串進行處理,稍微不注意的話,很容易出現類似NullPointerException這種簡單的錯誤,我們經常寫各種if來判斷處理這些非業務的邏輯。這時,我們可以利用大牛apache的輪子,通過其StringUtils里面的一些常用方法,改善我們的代碼,讓我們的業務代碼更簡潔、優雅。示例代碼:
@Slf4j public class AppTest { @Test public void stringUtils(){ String a = " "; String b = null; //判斷字符對象是否為空以及內容是否為空串(有空格則認為不是空串) log.info("StringUtils.isEmpty(a): {}", StringUtils.isEmpty(a)); //判斷字符對象是否為空以及內容是否為空串(有空格也會認為是空串) log.info("StringUtils.isBlank(a): {}", StringUtils.isBlank(a)); //當b=null時,如果b.trim()則會報空指針異常,使用StringUtils.trim(b)可以避免 log.info("StringUtils.trim(d): {}", StringUtils.trim(b)); String num = "12.3"; //當b=null時,如果b.trim()則會報空指針異常,使用StringUtils.trim(b)可以避免 log.info("org.apache.commons.lang3.StringUtils.isNumericSpace(): {} isNumber: {}", num, StringUtils.isNumericSpace(b)); log.info("com.alibaba.druid.util.StringUtils.isNumber(): {} isNumber: {}", num, com.alibaba.druid.util.StringUtils.isNumber(num)); } }
注意:common-lang3中的StringUtils. isNumeric()或isNumericSpace()並不能判斷字符串中帶小數點的數字值字符為數字。可以通過com.alibaba.druid.util.StringUtils.isNumber(str),此方法來判斷。
1.2 org.apache.commons.lang3.time.DateFormatUtils/DateUtils
時間轉換工具類:
@Test public void dateFormatUtils() throws Exception{ String pattern = "yyyy-MM-dd HH:mm:ss"; String timeStr = DateFormatUtils.format(new Date(), pattern); long timestamp = DateUtils.parseDate(timeStr, pattern).getTime(); log.info("==> current time: {}", timeStr); log.info("==> current time timestamp: {}", timestamp); }
總結
- StringUtils.isEmpty(str)/StringUtils.isNotEmpty(str): 判斷字符對象是否為null或空串(有空格則認為不是空串)
- StringUtils.isBlank(str)/StringUtils.isNotBlank(str): 判斷字符對象是否為null或空串(有空格也會認為是空串)
- DateFormatUtils.format(date, pattern): 將Date時間對象按表達式的格式轉換成時間字符串
- DateUtils.parseDate(timeStr, pattern): 將時間字符串反轉成Date對象
- ToStringBuilder.reflectionToString(obj): 將對象內容轉換成字符串輸出(下一節有使用到)
- ...
對於學習某個工具類,我們可以通過Intellij IDEA中可通過打開此類的源代碼,然后通過快捷鍵(MacOS: command+7; Windows: Alt+7)打開查看類方法列表(Structure),從方法名字上大概可以看出具體有那些適合自己使用的方法。
以上示例使用到的jar包可通過maven的pom.xml文件依賴導入:
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.8.1</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.9</version> </dependency>
2.common-beanutils庫
Map、JavaBean是我們日常業務代碼中經常使用到的2種類,有時因為業務原因,Map、JavaBean需要相互轉換copy啥的操作時,如果手動set/put,字段多的時候,就要吐血了。這里我們推薦使用BeanUtils來簡化我們的代碼
2.1.org.apache.commons.beanutils.BeanUtils類
@Test public void beanUtils() throws InvocationTargetException, IllegalAccessException { CompanyBean bean = new CompanyBean(); bean.setId(1); bean.setName("中國移動廣州分公司"); bean.setAddress("廣州市天河區中山大道"); bean.setTel("020-10086000"); CompanyBean destObj = new CompanyBean(); //復制bean之間復制內容, 新對象destObj需要先實例化 BeanUtils.copyProperties(destObj, bean); //ToStringBuilder類來自commons-lang3庫:將對象內容轉換成字符串輸出,方便於日志輸出 log.info("destObj from BeanUtils.copyProperties: {}", ToStringBuilder.reflectionToString(destObj)); Map<String, Object> map = new HashMap<>(); map.put("id", 2); map.put("name", "中國聯通廣州分公司"); map.put("address", "廣州市天河區中山大道2號"); map.put("tel", "020-10000110"); //將map(key,value)映射成bean BeanUtils.populate(destObj, map); log.info("destObj from BeanUtils.populate: {}", ToStringBuilder.reflectionToString(destObj)); //復制對象,與copyProperties()方法比較,這里新對象可以不先實例化 CompanyBean cloneBean = (CompanyBean)BeanUtils.cloneBean(destObj); log.info("cloneBean from BeanUtils.cloneBean: {}", ToStringBuilder.reflectionToString(cloneBean)); //將JavaBean轉換成Map Map newMap = BeanUtils.describe(cloneBean); log.info("newMap from BeanUtils.describe: {}", new Gson().toJson(newMap)); }
日志輸出如下:
2019-01-19 13:17:21.064 [main] INFO com.monbuilder.AppTest - destObj from BeanUtils.copyProperties: com.monbuilder.bean.CompanyBean@10683d9d[id=1,name=中國移動廣州分公司,address=廣州市天河區中山大道1號,tel=020-10086000] 2019-01-19 13:17:21.070 [main] INFO com.monbuilder.AppTest - destObj from BeanUtils.populate: com.monbuilder.bean.CompanyBean@10683d9d[id=2,name=中國聯通廣州分公司,address=廣州市天河區中山大道2號,tel=020-10000110] 2019-01-19 13:48:14.966 [main] INFO com.monbuilder.AppTest - newMap from BeanUtils.describe: {"address":"廣州市天河區中山大道2號","name":"中國聯通廣州分公司","tel":"020-10000110","id":"2","class":"class com.monbuilder.bean.CompanyBean"}
總結
- BeanUtils.copyProperties(destObj, sourceObj): JavaBean之間內容的復制
- BeanUtils.cloneBean(obj): 復制對象
- BeanUtils.populate(destObj, sourceMap): Map轉換成JavaBean
- BeanUtils.describe(bean): 將JavaBean轉換成Map
3.commons-io庫
org.apache.commons.io.IOUtils類
這個io工具類非常有用,當我們在處理流的過程中,經常需要把流與字節數組之間相互轉換,以及在處理完之后,關閉流等等這些操作時,我們需要寫挺多處理邏輯,close時還需要寫if判空啥的,但是使用了這個IOUtil后,我們的處理代碼或簡潔非常多的。
@Test public void ioUtils() throws IOException { InputStream io = this.getClass().getClassLoader().getResourceAsStream("README.md"); BufferedReader br = new BufferedReader(new InputStreamReader(io)); log.info("==> IOUtils.toString(br): {}", IOUtils.toString(br)); IOUtils.closeQuietly(br); IOUtils.closeQuietly(io); } 2019-01-19 14:29:26.140 [main] INFO com.monbuilder.AppTest - ==> IOUtils.toString(br): toolkit-demo,工具類庫使用示例
上面只是簡單的展示將文件流內容轉換成字符串,之后再關閉流,是不是非常簡潔呢?IOUtils里面還有非常多的好方法可以使用,這些可以根據自己在具體的工作場景下,查看IOUtils的方法列表,找到自己需要的方法
總結
IOUtils常用的方法有:
- IOUtils.closeQuietly(obj): 可關閉流SocketSocketServer等多種對象
- IOUtils.copy(InputStream, Writer): 復制輸入流
- IOUtils.write(byte[], OutputStream): 將字節數組轉換成流
- IOUtils.toByteArray(InputStream): 將輸入流轉換成字節數組
- IOUtils.toInputStream(String): 將字符串轉換成輸入流
- IOUtils.toString(InputStream): 將輸入流轉換成字符串
上面介紹的都是來自於apache官方的類庫,還有好多類與方法有待我們發掘使用。另外,還介紹另1個非常有名的工具類庫:guava,來自於Google;功能也有類似的,當然也有很多的擴展使用,本文就不再詳細介紹了。
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>23.2-jre</version>
</dependency>
JSON工具類
在如今REST API盛行的年代,前后端分離成為標配,json成為兩者之間的傳輸橋梁,在我們工作做打交道肯定非常頻繁咯。在Java開發中,JSON工具類的選擇並不少:
- fastjson 阿里巴巴出品,轉換快,但表現不夠穩定
- Gson google出品,使用簡單,輕量
- Jackson spring官方使用,性能快,轉換快,配置更靈活,不同場景下表現更穩定
比較推薦使用的是Jackson,如果我們使用Spring Boot或Spring Cloud時,構建web項目里面內置的json庫就是Jackson庫。
下面通過Jackson庫簡單封裝成JavaBean/json互轉的工具類:
package com.monbuilder.util; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import java.text.SimpleDateFormat; /*** * JSON轉換工具類 * @author <a href="mailto:lcbiao34@gmail.com">Builder34</a> * @date 2018-11-01 11:14:26 * */ @Slf4j public class JacksonUtil { private static ObjectMapper objectMapper = new ObjectMapper(); static { objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true); objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); objectMapper.configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true); objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); // 設置輸入時忽略JSON字符串中存在而Java對象實際沒有的屬性 objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); //設置不輸出值為 null 的屬性 objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); } /** * 將JSON字符串根據指定的Class反序列化成Java對象(轉換過程中出現異常則返回null對象) * * @param json JSON字符串 * @param objClass JavaObject對象Class * @return 反序列化生成的Java對象 * */ public static <T> T toJavaObject(String json, Class<T> objClass) { try { return objectMapper.readValue(json, objClass); } catch (Exception e) { log.error("", e); return null; } } /** * 將Java對象序列化成JSON字符串(轉換過程中出現異常則返回空對象json串"{}") * * @param obj 待序列化生成JSON字符串的Java對象 * @return JSON字符串 */ public static String toJsonString(Object obj) { try { return objectMapper.writeValueAsString(obj); } catch (Exception e) { log.error("",e); } return "{}"; } }
運用上面的工具類,示例:
@Test public void jsonUtils(){ CompanyBean bean = new CompanyBean(); bean.setId(1); bean.setName("中國移動廣州分公司"); bean.setAddress("廣州市天河區中山大道1號"); bean.setTel("020-10086000"); log.info("==> JacksonUtil.toJsonString(bean): {}", JacksonUtil.toJsonString(bean)); String json = JacksonUtil.toJsonString(bean); log.info("==> JacksonUtil.toJavaObject: {}", ToStringBuilder.reflectionToString(JacksonUtil.toJavaObject(json, CompanyBean.class))); } 2019-01-19 15:42:16.081 [main] INFO com.monbuilder.AppTest - ==> JacksonUtil.toJsonString(bean): {"id":1,"name":"中國移動廣州分公司","address":"廣州市天河區中山大道1號","tel":"020-10086000"} 2019-01-19 15:42:16.144 [main] INFO com.monbuilder.AppTest - ==> JacksonUtil.toJavaObject: com.monbuilder.bean.CompanyBean@376a0d86[id=1,name=中國移動廣州分公司,address=廣州市天河區中山大道1號,tel=020-10086000]
上面涉及到的示例代碼,皆可以通過打開Github地址[https://github.com/Builder34/toolkit-demo] 獲取。
https://www.toutiao.com/i6648120854502703620/?tt_from=weixin&utm_campaign=client_share&wxshare_count=1×tamp=1548034130&app=news_article&utm_source=weixin&iid=54172054558&utm_medium=toutiao_ios&group_id=6648120854502703620
輪子非常多,當然我們可以重復造輪子,但是我們更提倡的是使用已有優秀的輪子(工具類),開發出更簡潔、優雅、業務邏輯更清晰的代碼。