求求你了,不要再自己实现这些逻辑了,开源工具类不香吗?

开发 开发工具
最近公司来了一批实习生,阿粉负责带一个。这位小师弟说实话,基本功很扎实,做事也非常靠谱,深得阿粉真传。

 最近公司来了一批实习生,阿粉负责带一个。这位小师弟说实话,基本功很扎实,做事也非常靠谱,深得阿粉真传。

[[325347]]

 

不过最近给其 Review 代码的时候,阿粉发现小师弟有些代码逻辑有些繁琐,有些代码阿粉看来可以用一些开源工具类实现,不需要自己重复实现。

不过这也是正常的,阿粉刚入行的时候写的代码也是这样,这几年慢慢接触了一些开源工具类,逐渐积累。现在写代码才会直接用工具类替换自己实现的这些繁琐的逻辑。

于是阿粉给小师弟分享了几个自己常用的开源工具类,小师弟学完直呼:『666』。

 

 

 

[[325348]]

 

这里阿粉抛砖引玉,分享几个常用的工具类,希望帮助到刚入行的同学们。其他编程老司机如果还有其他好用的工具类,欢迎评论区分享。

下文主要分享这几个方向的常用工具类:

 

 

 

 

字符串相关工具类

Java 中 String 应该是日常用的最多一个类吧,平常我们很多代码需要围绕 String ,做一些处理。

JDK 提供 String API 虽然比较多,但是功能比较基础,通常我们需要结合 String 多个方法才能完成一个业务功能。

下面介绍一下 Apache 提供的一个工具类 StringUtils.

Maven Pom 信息如下:

  1. <dependency> 
  2.     <groupId>org.apache.commons</groupId> 
  3.     <artifactId>commons-lang3</artifactId> 
  4.     <version>3.10</version> 
  5. </dependency> 

commons-lang 有两个版本,一个是 commons-lang3 ,一个是 commons-lang 。

commons-lang 是老版本,已经很久没有维护了。

commons-lang3 是一直在维护的版本,推荐直接使用这个版本。

注意:如果你系统已经有 commons-lang,注意如果直接替换成 commons-lang3,将会编译错误。commons-lang3 中相关类与 commons-lang 一样,但是包名不一样。

判断字符串是否为空

判断字符串是否为空,想必每个人应该都写过吧:

 

  1. if (null == str || str.isEmpty()) { 
  2.  

虽然这段代码非常简单,但是说实话,阿粉以前还是在这里犯过空指针的异常的。

 

使用 StringUtils ,上面代码可以替换下面这样:

 

  1. if (StringUtils.isEmpty(str)) { 
  2.  

StringUtils 内部还有一个方法 isBlank,也是用来判断字符串是否为空,两个方法比较相近,比较搞混,主要区别如下:

 

  1. // 如果字符串都是空格的话, 
  2. StringUtils.isBlank(" ")       = true
  3. StringUtils.isEmpty(" ")       = false;   

判断字符串是否为空,使用频率非常高,这里大家可以使用 IDEA Prefix 的功能,输入直接生成判空语句。

 

 

 

 

字符串固定长度

这个通常用于字符串需要固定长度的场景,比如需要固定长度字符串作为流水号,若流水号长度不足,,左边补 0 。

这里当然可以使用 String#format 方法,不过阿粉觉得比较麻烦,这里可以这样使用:

 

  1. // 字符串固定长度 8位,若不足,往左补 0 
  2. StringUtils.leftPad("test", 8, "0"); 

另外还有一个 StringUtils#rightPad,这个方法与上面方法正好相反。

字符串关键字替换

StringUtils 提供一些列的方法,可以替换某些关键字:

 

  1. // 默认替换所有关键字 
  2. StringUtils.replace("aba""a""z")   = "zbz"
  3. // 替换关键字,仅替换一次 
  4. StringUtils.replaceOnce("aba""a""z")   = "zba"
  5. // 使用正则表达式替换 
  6. StringUtils.replacePattern("ABCabc123""[^A-Z0-9]+""")   = "ABC123"; 
  7. ....    

字符串拼接

字符串拼接是个常见的需求,简单办法使用 StringBuilder 循环遍历拼接:

 

  1. String[] array = new String[]{"test""1234""5678"}; 
  2. StringBuilder stringBuilder = new StringBuilder(); 
  3.  
  4. for (String s : array) { 
  5.     stringBuilder.append(s).append(";"); 
  6. // 防止最终拼接字符串为空  
  7. if (stringBuilder.length() > 0) { 
  8.     stringBuilder.deleteCharAt(stringBuilder.length() - 1); 
  9. System.out.println(stringBuilder.toString()); 

上面业务代码不太难,但是需要注意一下上面这段代码非常容易出错,容易抛出 StringIndexOutOfBoundsException。

这里我们可以直接使用以下方法获取拼接之后字符串:

 

  1. StringUtils.join(["a""b""c"], ",")    = "a,b,c" 

StringUtils 只能传入数组拼接字符串,不过我比较喜欢集合拼接,所以再推荐下 Guava 的 Joiner。

实例代码如下:

 

  1. String[] array = new String[]{"test""1234""5678"}; 
  2. List<String> list=new ArrayList<>(); 
  3. list.add("test"); 
  4. list.add("1234"); 
  5. list.add("5678"); 
  6. StringUtils.join(array, ","); 
  7.  
  8. // 逗号分隔符,跳过 null 
  9. Joiner joiner=Joiner.on(",").skipNulls(); 
  10. joiner.join(array); 
  11. joiner.join(list); 

字符串拆分

有字符串拼接,就会有拆分字符串的需求,同样的 StringUtils 也有拆分字符串的方法。

 

  1. StringUtils.split("a..b.c"'.')   = ["a""b""c"
  2. StringUtils.splitByWholeSeparatorPreserveAllTokens("a..b.c"".")= ["a","""b""c"

ps:注意以上两个方法区别。

StringUtils 拆分之后得到是一个数组,我们可以使用 Guava 的

 

  1. Splitter splitter = Splitter.on(","); 
  2. // 返回是一个 List 集合,结果:[ab, , b, c] 
  3. splitter.splitToList("ab,,b,c"); 
  4. // 忽略空字符串,输出结果 [ab, b, c] 
  5. splitter.omitEmptyStrings().splitToList("ab,,b,c"

StringUtils 内部还有其他常用的方法,小伙伴可以自行查看其 API。

日期相关工具类

DateUtils/DateFormatUtils

JDK8 之前,Java 只提供一个 Date 类,平常我们需要将 Date 按照一定格式转化成字符串,我们需要使用 SimpleDateFormat。

 

  1. SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 
  2. // Date 转 字符串 
  3. simpleDateFormat.format(new Date()); 
  4. // 字符串 转 Date 
  5. simpleDateFormat.parse("2020-05-07 22:00:00"); 

代码虽然简单,但是这里需要注意 SimpleDateFormat,不是线程安全的,多线程环境一定要注意使用安全。

这里阿粉推荐 commons-lang3 下的时间工具类DateUtils/DateFormatUtils,解决 Date 与字符串转化问题。

ps:吐槽一下,你们工程中有没有多个叫 DateUtils 类?阿粉发现我们现有工程,多个模块有提供这个类,每个实现大同小异。

使用方法非常简单:

 

  1. // Date 转化为字符串 
  2. DateFormatUtils.format(new Date(),"yyyy-MM-dd HH:mm:ss"); 
  3. // 字符串 转 Date 
  4. DateUtils.parseDate("2020-05-07 22:00:00","yyyy-MM-dd HH:mm:ss"); 

除了格式转化之外,DateUtils 还提供时间计算的相关功能。

 

  1. Date now = new Date(); 
  2. // Date 加 1 天 
  3. Date addDays = DateUtils.addDays(now, 1); 
  4. // Date 加 33 分钟 
  5. Date addMinutes = DateUtils.addMinutes(now, 33); 
  6. // Date 减去 233 秒 
  7. Date addSeconds = DateUtils.addSeconds(now, -233); 
  8. // 判断是否 Wie 同一天 
  9. boolean sameDay = DateUtils.isSameDay(addDays, addMinutes); 
  10. // 过滤时分秒,若 now 为 2020-05-07 22:13:00 调用 truncate 方法以后 
  11. // 返回时间为 2020-05-07 00:00:00 
  12. Date truncate = DateUtils.truncate(now, Calendar.DATE); 

JDK8 时间类

JDK8 之后,Java 将日期与时间分为 LocalDate,LocalTime,功能定义更加清晰,当然其也提供一个 LocalDateTime,包含日期与时间。这些类相对于 Date 类优点在于,这些类与 String 类一样都是不变类型,不但线程安全,而且不能修改。

ps:仔细对比 mysql 时间日期类型 DATE,TIME,DATETIME,有没有感觉差不多

现在 mybatis 等 ORM 框架已经支持 LocalDate 与 JDBC 时间类型转化,所以大家可以直接将时间字段实际类型定义为 JDK8 时间类型,然后再进行相关转化。

如果依然使用的是 Date 类型,如果需要使用新的时间类型,我们需要进行相关转化。两者之间进行转化, 稍微复杂一点,我们需要显示指定当前时区。

 

  1. Date now = new Date(); 
  2. // Date-----> LocalDateTime 这里指定使用当前系统默认时区 
  3. LocalDateTime localDateTime = now.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(); 
  4. // LocalDateTime------> Date 这里指定使用当前系统默认时区 
  5. Date date = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant()); 

接下来我们使用 LocalDateTime 进行字符串格式化。

 

  1. // 按照 yyyy-MM-dd HH:mm:ss 转化时间 
  2. LocalDateTime dateTime = LocalDateTime.parse("2020-05-07 22:34:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); 
  3. // 将 LocalDateTime 格式化字符串 
  4. String format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(dateTime); 

另外我们使用 LocalDateTime 获取当前时间年份,月份特别简单:

 

  1. LocalDateTime now = LocalDateTime.now(); 
  2. // 年 
  3. int year = now.getYear(); 
  4. // 月 
  5. int month = now.getMonthValue(); 
  6. // 日 
  7. int day = now.getDayOfMonth(); 

最后我们还可以使用 LocalDateTime 进行日期加减,获取下一天的时间:

 

  1. LocalDateTime now = LocalDateTime.now(); 
  2. // 当前时间加一天 
  3. LocalDateTime plusDays = now.plusDays(1l); 
  4. // 当前时间减一个小时 
  5. LocalDateTime minusHours = now.minusHours(1l); 
  6. // 还有很多其他方法 

总之 JDK8 提供的时间类非常好用,还没用过小伙伴,可以尝试下。

集合/数组相关

集合与数组我们日常也需要经常使用,也需要对其进行判空:

 

  1. if (null == list || list.isEmpty()) { 
  2.  

ps: 数组、Map 集合与其类似

上面代码如字符串判空一样写起来都非常简单,但是也比较容易写出会抛出空指针异常的代码。这里我们可以使用 commons-collections 提供工具类。

pom 信息:

  1. <dependency> 
  2.     <groupId>org.apache.commons</groupId> 
  3.     <artifactId>commons-collections4</artifactId> 
  4.     <version>4.4</vesion> 
  5. </dependency> 

ps: 还有一个低版本的 ,artifactId 为 commons-collections

我们可以使用 CollectionUtils/MapUtils进行判空判断。

 

  1. // List/Set 集合判空 
  2. if(CollectionUtils.isEmpty(list)){ 
  3.  
  4. // Map 等集合进行判空 
  5. if (MapUtils.isEmpty(map)) { 
  6.      

至于数组判空判断需要使用 commons-lang 下的 ArrayUtils进行判断:

 

  1. // 数组判空 
  2. if (ArrayUtils.isEmpty(array)) { 
  3.      

除此之外还有一些列的对于集合增强方法,比如快速将数组加入到现有集合中:

 

  1. List<String> listA = new ArrayList<>(); 
  2. listA.add("1"); 
  3. listA.add("2"); 
  4. listA.add("3"); 
  5. String[] arrays = new String[]{"a""b""c"}; 
  6. CollectionUtils.addAll(listA, arrays); 

其他方法感兴趣同学可以再自行研究下,另外 Guava 中也有提供对于集合的操作增强类 Lists/Maps,这个可以看下阿粉之前写的:老司机阿粉带你玩转 Guava 集合类

I/O 相关

JDK 有提供一系列的类可以读取文件等,不过阿粉觉得那些类有些晦涩难懂,实现一个小功能可能还要写好多代码,而且还不一定能写对。

阿粉推荐一下 Apache 提供的 commons-io 库,增强 I/O 操作,简化操作难度。pom 信息:

  1. <dependency> 
  2.     <groupId>commons-io</groupId> 
  3.     <artifactId>commons-io</artifactId> 
  4.     <version>2.6</version> 
  5. </dependency> 

FileUtils-文件操作工具类

文件操作工具类提供一系列方法,可以让我们快速读取写入文件。

快速实现文件/文件夹拷贝操作 ,FileUtils.copyDirectory/FileUtils.copyFile

 

  1. // 拷贝文件 
  2. File fileA = new File("E:\\test\\test.txt"); 
  3. File fileB = new File("E:\\test1\\test.txt"); 
  4. FileUtils.copyFile(fileA,fileB); 

使用 FileUtils.listFiles 获取指定文件夹上所有文件

 

  1. // 按照指定文件后缀如java,txt等去查找指定文件夹的文件 
  2. File directory = new File("E:\\test"); 
  3. FileUtils.listFiles(directory, new String[]{"txt"}, false); 

使用 FileUtils.readLines 读取该文件所有行。

 

  1. // 读取指定文件所有行 不需要使用 while 循环读取流了 
  2. List<String> lines = FileUtils.readLines(fileA) 

有读就存在写,可以使用 FileUtils.writeLines,直接将集合中数据,一行行写入文本。

 

  1. // 可以一行行写入文本 
  2. List<String> lines = new ArrayList<>(); 
  3. ..... 
  4. FileUtils.writeLines(lines) 

IOUtils-I/O 操作相关工具类

FileUtils 主要针对相关文件操作,IOUtils 更加针对底层 I/O,可以快速读取 InputStream。实际上 FileUtils 底层操作依赖就是 IOUtils。

IOUtils可以适用于一个比较试用的场景,比如支付场景下,HTTP 异步通知场景。如果我们使用 JDK 原生方法写:

从 Servlet 获取异步通知内容

 

  1. byte[] b = null
  2. ByteArrayOutputStream baos = null
  3. String respMsg = null
  4. try { 
  5.     byte[] buffer = new byte[1024]; 
  6.     baos = new ByteArrayOutputStream(); 
  7.    // 获取输入流 
  8.     InputStream in = request.getInputStream(); 
  9.     for (int len = 0; (len = in.read(buffer)) > 0; ) { 
  10.         baos.write(buffer, 0, len); 
  11.     } 
  12.     b = baos.toByteArray(); 
  13.     baos.close(); 
  14.    // 字节数组转化成字符串 
  15.     String reqMessage = new String(b, "utf-8"); 
  16. } catch (IOException e) { 
  17.    
  18. } finally { 
  19.     if (baos != null) { 
  20.         try { 
  21.             baos.close(); 
  22.         } catch (IOException e) { 
  23.             
  24.         } 
  25.     } 

上面代码说起来还是挺复杂的。不过我们使用 IOUtils,一个方法就可以简单搞定:

 

  1. // 将输入流信息全部输出到字节数组中 
  2. byte[] b = IOUtils.toByteArray(request.getInputStream()); 
  3. // 将输入流信息转化为字符串 
  4. String resMsg = IOUtils.toString(request.getInputStream()); 

ps: InputStream 不能被重复读取

计时

编程中有时需要统计代码的的执行耗时,当然执行代码非常简单,结束时间与开始时间相减即可。

 

  1. long start = System.currentTimeMillis();   //获取开始时间 
  2.  
  3. //其他代码 
  4. //... 
  5. long end = System.currentTimeMillis(); //获取结束时间 
  6.  
  7. System.out.println("程序运行时间: " + (end - start) + "ms"); 

虽然代码很简单,但是非常不灵活,默认情况我们只能获取 ms 单位,如果需要转换为秒,分钟,就需要另外再计算。

这里我们介绍 Guava Stopwatch 计时工具类,借助他统计程序执行时间,使用方式非常灵活。

commons-lang3 与 Spring-core 也有这个工具类,使用方式大同小异,大家根据情况选择。

 

  1. // 创建之后立刻计时,若想主动开始计时 
  2. Stopwatch stopwatch = Stopwatch.createStarted(); 
  3. // 创建计时器,但是需要主动调用 start 方法开始计时 
  4. // Stopwatch stopwatch = Stopwatch.createUnstarted(); 
  5. // stopWatch.start(); 
  6. // 模拟其他代码耗时 
  7. TimeUnit.SECONDS.sleep(2l); 
  8.  
  9. // 当前已经消耗的时间 
  10. System.out.println(stopwatch.elapsed(TimeUnit.SECONDS));; 
  11.  
  12. TimeUnit.SECONDS.sleep(2l); 
  13.  
  14. // 停止计时 未开始的计时器调用 stop 将会抛错 IllegalStateException 
  15. stopwatch.stop(); 
  16. // 再次统计总耗时 
  17. System.out.println(stopwatch.elapsed(TimeUnit.SECONDS));; 
  18. // 重新开始,将会在原来时间基础计算,若想重新从 0开始计算,需要调用 stopwatch.reset() 
  19. stopwatch.start(); 
  20. TimeUnit.SECONDS.sleep(2l); 
  21. System.out.println(stopwatch.elapsed(TimeUnit.SECONDS)); 

输出结果为:

 

总结

今天阿粉抛砖引玉,介绍了字符串、日期、数组/集合、I/O、计时等工具类,简化日常业务代码。大家看完可以尝试一下,不得不说,这些工具类真香!

责任编辑:华轩 来源: Java极客技术
相关推荐

2020-10-12 10:45:44

nullava程序员

2021-05-11 07:10:18

标准库DjangoOS

2024-02-01 08:21:40

2020-12-11 09:24:19

Elasticsear存储数据

2020-06-15 08:12:51

try catch代码处理器

2020-12-15 08:06:45

waitnotifyCondition

2019-11-18 10:16:37

工程师开发网络

2019-11-18 10:05:43

程序员技能开发者

2021-12-05 23:17:18

iOS苹果系统

2022-10-27 21:34:28

数据库机器学习架构

2020-09-22 09:05:45

MySQLUTF-8utf8mb4

2020-11-09 08:22:29

程序员 IT科技

2021-12-03 10:46:49

ELKGraylog运维

2020-01-21 21:15:16

WiFi网络WiFi6

2021-12-02 06:34:34

GraylogELK日志

2020-12-01 11:18:34

对外接口枚举

2021-01-11 08:03:30

阿里中台项目

2020-07-03 15:10:35

Java Rust 开发

2021-05-26 11:11:01

代码Java工具库

2021-09-30 06:13:36

打印日志error
点赞
收藏

51CTO技术栈公众号