最近公司有一批实习生,阿芬负责带队。说实话,这个小师弟基本功扎实,做事也很靠谱,深得阿粉真传。不过最近阿芬在帮他看代码的时候发现小弟有些代码逻辑有点繁琐,有些代码用一些开源工具就可以实现,不需要再重复实现你自己。但这也很正常。阿芬刚入行时写的代码也是如此。这几年,他逐渐接触了一些开源工具,也逐渐积累起来。只有现在写代码的时候,才能直接用工具类代替自己实现的繁琐逻辑。于是阿芬给小弟分享了几个常用的开源工具,小弟学完直呼:“666”。在这里,阿芬抛砖引玉,分享几个常用的工具,希望能对刚入行的同学有所帮助。如果其他编程老司机有其他好用的工具,欢迎在评论区分享。下面主要分享这几个方向的常用工具类:String相关的工具类Java中的String应该是日常生活中最常用的类了。通常我们很多代码都需要围绕String做一些处理。JDK提供的StringAPI虽然很多,但是功能都比较基础。通常我们需要组合String的多个方法来完成一个业务功能。下面介绍一个Apache提供的工具类StringUtils.MavenPom。信息如下:org.apache.commonscommons-lang33.10commons-lang有两个版本,一个是commons-lang3,另一个是commons-lang。commons-lang是老版本,很久没有维护了。commons-lang3是一直维护的版本,建议直接使用这个版本。注意:如果你的系统已经有commons-lang,注意如果直接替换成commons-lang3,会编译错误。commons-lang3中的相关类与commons-lang相同,只是包名不同。判断字符串是否为空判断字符串是否为空,大家应该都写过:if(null==str||str.isEmpty()){}这段代码虽然很简单,但是说实话,啊之前有粉丝在这里提交过空指针异常。使用StringUtils,上面的代码可以换成如下:if(StringUtils.isEmpty(str)){}StringUtils内部还有一个方法isBlank,也是用来判断字符串是否为空的。两种方法相似也容易混淆,主要区别如下://如果字符串都是空格,StringUtils.isBlank("")=true;StringUtils.isEmpty("")=false;判断字符串是否为空,使用频率很高,这里可以使用IDEAPrefix的功能,输入直接生成空语句。Stringfixedlength这通常用在字符串需要固定长度的场景,比如需要一个固定长度的字符串作为序号,如果序号的长度不够,就在左边补0。当然这里也可以使用String#format的方法,但是阿芬觉得比较麻烦,所以可以这样使用://字符串的固定长度为8位,不够就在后面加0leftStringUtils.leftPad("测试",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循环连接:String[]array=newString[]{"test","1234","5678"};StringBuilderstringBuilder=newStringBuilder();for(Strings:array){stringBuilder.append(s).append(";");}//防止最后拼接的字符串为空if(stringBuilder.length()>0){stringBuilder.deleteCharAt(stringBuilder.length()-1);}System.out.println(stringBuilder.toString());上面的业务代码并不太难,但是需要注意上面的代码非常容易出错,很容易抛出StringIndexOutOfBoundsException。这里我们可以直接使用如下方法获取拼接后的字符串:StringUtils.join(["a","b","c"],",")="a,b,c"StringUtils只能传入数组拼接字符串,不过我更喜欢集合拼接,所以推荐Guava的Joiner。示例代码如下:String[]array=newString[]{"test","1234","5678"};Listlist=newArrayList<>();list.add("test");list.add("1234");list.add("5678");StringUtils.join(array,",");//逗号分隔符,跳过nullJoinerjoiner=Joiner.on(",").skipNulls();joiner.join(array);joiner.join(列表);字符串拆分如果有字符串拼接,就会有拆分字符串的需求。同样,StringUtils也有一个拆分字符串的方法。StringUtils.split("a..b.c",'.')=["a","b","c"]StringUtils.splitByWholeSeparatorPreserveAllTokens("a..b.c",".")=["a","","b","c"]ps:注意上面两种方式的区别。StringUtils拆分后得到一个数组,可以用Guava的Splittersplitter=Splitter.on(",");//返回的是一个List集合,结果:[ab,,b,c]splitter.splitToList("ab,,b,c");//忽略空串,输出结果[ab,b,c]splitter.omitEmptyStrings().splitToList("ab,,b,c")里面还有其他常用的方法StringUtils,小伙伴可以自行查看自己的API。日期相关的工具类DateUtils/DateFormatUtilsJDK8之前,Java只提供了一个Date类,通常我们需要将Date按照一定的格式转换成字符串,就需要用到SimpleDateFormat。SimpleDateFormatsimpleDateFormat=newSimpleDateFormat("yyyy-MM-ddHH:mm:ss");//日期转字符串simpleDateFormat.format(newDate());//字符串转日期simpleDateFormat.parse("2020-05-0722:00:00");代码虽然简单,但是这里需要注意SimpleDateFormat,它不是线程安全的。在多线程环境下使用一定要注意安全。这里阿凡推荐commons-lang3下的时间工具类DateUtils/DateFormatUtils来解决Date和字符串的转换问题。ps:开个玩笑,你的项目中有多个类叫DateUtils吗?阿芬发现在我们现有的项目中,有多个模块都提供了这个类,而且每个实现都大同小异。使用方法很简单://日期转为字符串DateFormatUtils.format(newDate(),"yyyy-MM-ddHH:mm:ss");//字符串转为DateDateUtils.parseDate("2020-05-0722:00:00","yyyy-MM-ddHH:mm:ss");除了格式转换,DateUtils还提供了时间计算相关的功能。Datenow=newDate();//日期加1天DateaddDays=DateUtils.addDays(now,1);//日期加33分钟DateaddMinutes=DateUtils.addMinutes(now,33);//日期减233秒DateaddSeconds=DateUtils.addSeconds(now,-233);//判断Wie是否是同一天booleansameDay=DateUtils.isSameDay(addDays,addMinutes);//过滤时分秒,如果now是2020-05-0722:13:00调用truncate方法后//返回时间为2020-05-0700:00:00Datetruncate=DateUtils.truncate(now,Calendar.DATE);JDK8时间类JDK8之后,Java将日期和时间分为LocalDate和LocalTime,功能定义更加清晰。提供包含日期和时间的LocalDateTime。这些类相对于Date类的优势在于,这些类和String类一样,都是不可变类型,不仅线程安全,而且不可修改。ps:仔细比较mysql的时间日期类型DATE、TIME、DATETIME。你觉得他们几乎一样吗?现在mybatis等ORM框架已经支持LocalDate和JDBC时间类型之间的转换,所以可以直接将时间字段的实际类型定义为JDK8时间类型,然后进行相关的转换。如果还是使用Date类型,如果需要使用新的时间类型,我们需要进行相关的转换。两者之间的转换,稍微复杂一点,我们需要显示和指定当前时区。Datenow=newDate();//Date----->LocalDateTime这里指定当前系统默认时区LocalDateTimelocalDateTime=now.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();//LocalDateTime------>Date指定使用当前系统默认时区Datedate=Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());接下来我们使用LocalDateTime进行字符串格式化。//根据yyyy-MM-ddHH:mm:ss转换时间LocalDateTimedateTime=LocalDateTime.parse("2020-05-0722:34:00",DateTimeFormatter.ofPattern("yyyy-MM-ddHH:mm:ss"));//格式化LocalDateTime字符串Stringformat=DateTimeFormatter.ofPattern("yyyy-MM-ddHH:mm:ss").format(dateTime);另外,我们使用LocalDateTime获取当前时间年、月,很简单:LocalDateTimenow=LocalDateTime.now();//年intyear=now.getYear();//月intmonth=now.getMonthValue();//天intday=now.getDayOfMonth();最后,我们还可以使用LocalDateTime对日期进行加减得到第二天的时间:LocalDateTimenow=LocalDateTime.now();//当前时间加一天LocalDateTimeplusDays=now.plusDays(1l);//当前时间减一小时LocalDateTimeminusHours=now.minusHours(1l);//反正还有很多方法JDK8提供的时间类非常好用。如果你还没有使用过它,你可以尝试一下。集合/数组我们日常生活中经常会用到相关的集合和数组,我们也需要判断它们是否为空:if(null==list||list.isEmpty()){}ps:Arrays,Map集合等类似的代码上面像字符判断null之类的写起来很简单,但是会抛出空指针异常的代码也比较容易写。这里我们可以使用commons-collections来提供实用类。pom信息:org.apache.commonscommons-collections44.4ps:还有一个低版本,artifactId对于commons-collections,我们可以使用CollectionUtils/MapUtils进行空判断。//List/Set集合为空if(CollectionUtils.isEmpty(list)){}//Map等集合判断为空if(MapUtils.isEmpty(map)){}至于数组判断,需要用commons-langArrayUtilsjudges//数组判断为空if(ArrayUtils.isEmpty(array)){}另外还有一些集合增强的方法,比如给已有的集合快速添加数组:ListlistA=newArrayList<>();listA.add("1");listA.add("2");listA.add("3");String[]arrays=newString[]{"a","b","c"};CollectionUtils.addAll(listA,数组);对其他方法感兴趣的同学可以自行研究。此外,Guava还提供了Lists/Maps,这是集合操作的增强类。你可以看看阿芬之前写的。:老司机阿芬带你玩番石榴收藏课。I/O相关的JDK提供了一系列的类,可以读取文件等,但是阿芬觉得那些类有点晦涩难懂,实现一个小功能可能要写很多代码,也不一定写正确。阿芬推荐Apache提供的commons-io库来增强I/O操作,简化操作。pom信息:commons-iocommons-io2.6FileUtils-文件操作工具类文件操作工具类提供了一个一系列让我们可以快速读写文件的方法。快速实现文件/文件夹复制操作,FileUtils.copyDirectory/FileUtils.copyFile//复制文件FilefileA=newFile("E:\\test\\test.txt");FilefileB=newFile("E:\\test1\\test.txt");FileUtils.copyFile(fileA,fileB);使用FileUtils.listFiles获取指定文件夹下的所有文件//根据指定文件后缀如java,txt等查找指定文件夹下的文件Filedirectory=newFile("E:\\test");FileUtils.listFiles(目录,newString[]{"txt"},false);使用FileUtils.readLines读取文件的所有行。//读取指定文件的所有行不需要使用while循环读取流。Listlines=FileUtils.readLines(fileA)读了就可以写。您可以使用FileUtils.writeLines直接逐行输入文本写入集合中的数据。//可以逐行写文本Listlines=newArrayList<>();.....FileUtils.writeLines(lines)IOUtils-I/O操作相关工具类FileUtils主要是相关的文件操作,而IOUtils更多的是针对Low-levelI/O,可以快速读取InputStream。其实FileUtils的底层运行依赖就是IOUtils。IOUtils可以应用到更多试用场景,比如支付场景,HTTP异步通知场景。如果我们使用JDKnative方法写:从Servlet获取异步通知内容byte[]b=null;ByteArrayOutputStreambaos=null;StringrespMsg=null;try{byte[]buffer=newbyte[1024];baos=newByteArrayOutputStream();//获取输入流InputStreamin=request.getInputStream();for(intlen=0;(len=in.read(buffer))>0;){baos.write(buffer,0,len);}b=baos.toByteArray();baos.close();//将字节数组转换成字符串StringreqMessage=newString(b,"utf-8");}catch(IOExceptione){}finally{if(baos!=null){try{宝。close();}catch(IOExceptione){}}}上面的代码比较复杂。但是我们使用IOUtils,一个方法很简单://将所有输入流信息输出到字节数组byte[]b=IOUtils.toByteArray(request.getInputStream());//将输入流信息转换为字符StringStringresMsg=IOUtils.toString(request.getInputStream());ps:InputStream不能重复读取。longstart=System.currentTimeMillis();//获取开始时间//其他代码//...longend=System.currentTimeMillis();//获取结束时间System.out.println("程序运行时间:"+(结束-开始)+“毫秒”);虽然代码很简单,但是很不灵活。默认情况下,我们只能获取ms的单位。如果需要换算成秒或者分,需要单独计算。这里介绍GuavaStopwatch计时工具类,用于统计程序的执行时间,使用非常灵活。commons-lang3和Spring-core也有这个工具类,使用方法也差不多,大家可以根据情况选择。//创建后立即计时,如果想主动开始计时Stopwatchstopwatch=Stopwatch.createStarted();//创建一个定时器,但是需要主动调用start方法开始计时//Stopwatchstopwatch=Stopwatch.createUnstarted();//stopWatch.start();//模拟其他代码耗时TimeUnit.SECONDS.sleep(2l);//当前耗时System.out.println(stopwatch.elapsed(TimeUnit.SECONDS));;TimeUnit.SECONDS.sleep(2l);//停止还未启动的定时器,调用stop会抛出错误IllegalStateExceptionstopwatch.stop();//重新统计总时间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、时序等工具,简化日常业务代码。看完可以试试,不得不说,这些工具真的很好吃!