ITPub博客

首页 > 应用开发 > Java > Hutool 工具不糊涂

Hutool 工具不糊涂

Java 作者:喝水会长肉 时间:2021-12-19 16:16:18 0 删除 编辑

 前言

这是我参与11月更文挑战的第3天,活动详情查看: 2021最后一次更文挑战 。还在对项目中的工具类和工具方法进行封装吗?让  Hutool 帮你,它是项目中  util 包的友好替代,覆盖了  Java 开发底层的方方面面,既是大型项目中解决小问题的利器,也是小项目中的效率担当,它能让你专注业务,极大地提升开发效率,可以最大程度地避免自行封装出现的小问题、小  Bug。所以,学会如何高效、准确地使用项目开发过程中所需的工具方法非常有必要,今天结合使用场景给大家分享一些实用的工具类方法,没讲清楚以及未涉及之处,望大家见谅,具体详情可参见  Hutool 官网 (hutool.cn) 。

引入

Hutool 包含对文件、流、加密解密、转码、正则、线程、XML 等 JDK 方法进行封装,放在不同的模块组件当中,当你需要对  Excel 进行操作时,你可以单独引入  hutool-poi 模块,当然分不清个模块之间功能,图省事,也可以通过引入  hutool-all 方式引入所有模块。

Maven


<dependency
>

    <groupId >cn .hutool < /groupId >
    <artifactId >hutool -all < /artifactId >
    <version > 5.7 .16 < /version >
< /dependency >

Gradle

implementation 'cn.hutool:hutool-all:5.7.16'

使用

下面给大伙分享一些经常使用且使用的工具方法,有用到过的欢迎留言评论哦 (^▽^)

Console 对象信息打印类

熟悉  JS 的掘友看到这两个方法一定不陌生,甚至是“旧交”了,其实  Hutool 中 的  Console 对象借鉴的就是  JS 中的语法糖。虽说是打印,和  System.out.println() / System.err.println() 还是有所不同的,最重要的是它支持  Slf4j 的字符串模版语法,会自动将对象(包括数组)转为字符串形式。

代码实例:



Console . log ( "this is array: {}" , new String [ ] { "Java" , "JavaScript" , "Python" } ) ;

Console . error ( "I'm a red error message." ) ;

这里的  {} 作为模版占位符,能够将逗号右边的变量值依次传入,从而以字符串的形式打印输出。

Convert 不同类型之间转换类

该类中封装了针对  Java 常见类型的转换,用于简化类型转换,同时对转换失败的异常捕获有着很好的封装,能够帮你减轻业务代码的臃肿,提升代码的优雅性,该工具类还是非常常用和实用的,必须安利一波୧(๑•̀◡•́๑)૭

代码实例:



// 转换为字符串
int number = 10 ;
Console . log ( "转换成字符串后:{}" , Convert . toStr (number ) ) ;

int [ ] arr = { 1 , 2 , 3 , 4 , 5 } ;
Console . log (Convert . toStr (arr , "Convert to string fail! This is default value." ) ) ;

// 转换为指定类型的数组
String [ ] letters = { "12" , "122" , "1223" , "1211" } ;
Console . log (Convert . toShortArray (letters ) ) ;
Console . log (Convert . toStrArray (arr ) ) ;

float [ ] floatArr = { 1.2F , 1.3F , 2.0F , 3.14f } ;
Integer [ ] integerArr = Convert . toIntArray (floatArr ) ;
Console . log (integerArr ) ; // [1, 1, 2, 3]

// 转换为日期对象
String strDate1 = "2021-10-11 12:03:29" ;
// toDate
Console . log ( "The string of data convert to Date: {}" , Convert . toDate (strDate1 ) ) ; // 2021-10-11 12:03:29
// toLocalDateTime
Console . log ( "The string of data convert to LocalDateTime: {}" , Convert . toLocalDateTime (strDate1 ) ) ; // 2021-10-11T12:03:29

// 转换成集合
String [ ] langs = { "Java" , "JavaScript" , "Python" , "C++" , "GoLang" , "TypeScript" , "Kotlin" } ;

// 通过 Convert.convert(Class<T>, Object) 方法可以将任意类型转换为指定类型
ArrayList arrayList = Convert . convert (ArrayList .class , langs ) ;
// 也可以这样转集合
List <String > langList = Convert . toList (String .class , langs ) ;
Console . log ( "String array is converted to ArrayList: {}" , arrayList ) ;
Console . log ( "String array is converted to List: {}" , langList ) ;
// 转成指定类型的集合
Object [ ] objArr = { "a" , "你" , "好" , "" , 1 } ;
// TypeReference 对象可以对嵌套泛型进行类型转换
List <String > strList = Convert . convert ( new TypeReference <List <String >> ( ) {
} , objArr ) ;
Console . log ( "使用 TypeReference 对象可以对嵌套泛型进行类型转换:{}" , strList ) ;

字符串转为  16 进制( Hex)和  Unicode 串


// 字符串转为 16 进制(Hex)

String desc = "大家好,我的名字叫 HUALEI !" ;
// 因为字符串牵涉到编码问题,因此必须传入编码对象
String hexStr = Convert . toHex (desc , CharsetUtil . CHARSET_UTF_8 ) ;
Console . log ( "将字符串转为 Hex 字符串:{}" , hexStr ) ; // e5a4a7e5aeb6e5a5bdefbc8ce68891e79a84e5908de5ad97e58fab204855414c454920efbc81

// Hex 字符串转换回去
String originStr = Convert . hexToStr (hexStr , CharsetUtil . CHARSET_UTF_8 ) ;
Console . log ( "将 Hex 字符串转换回原先字符串:{}" , originStr ) ;

/*
   如果把各种文字编码形容为各地的方言,那么 Unicode 就是世界各国合作开发的一种语言。

   字符串转为 Unicode(统一码 / 万国码 / 单一码),它是为了解决传统字符编码方案弊端(繁杂不统一,导致编码格式不一致引发的乱码问题)

       Unicode 为每种语言中的每个字符设定了 统一 并且 唯一 的 二进制编码
       以满足 跨语言、跨平台 进行 文本转换、处理 的需求
*/

// 将字符串转换成 Unicode
String unicodeStr = Convert . strToUnicode (desc ) ;
Console . log ( "字符串转换成 Unicode 串:{}" , unicodeStr ) ; // \u5927\u5bb6\u597d\uff0c\u6211\u7684\u540d\u5b57\u53eb HUALEI \uff01

字符编码方式转换(编码与解码)



String a = "我不是乱码" ;
// 使用 UTF8 字符编码解码为 ISO_8859_1 编码方式的字符串
String mess = Convert . convertCharset (a , CharsetUtil . UTF_8 , CharsetUtil . ISO_8859_1 ) ;
Console . log ( "ISO_8859_1 编码方式的中文乱码:{}" , mess ) ; // 转换后 mess 为乱码 => æˆ‘ä¸æ˜¯ä¹±ç 

// 使用 ISO_8859_1 字符编码解码为原先的 UTF8 编码方式的字符串,将乱码转为正确的编码方式:
String raw = Convert . convertCharset (mess , CharsetUtil . ISO_8859_1 , "UTF-8" ) ;
Console . log ( "将乱码转为正确的编码后:{}" , raw ) ; // 我不是乱码

中文大/小写数字、金额相关转换



// 金额转中文表达(最多保留到小数点后两位)
double money = 18.88D ;
String chineseWord = Convert . digitToChinese (money ) ;
Console . log ( "金额转中文表达:{}" , chineseWord ) ; // 壹拾捌元捌角捌分

// 金额转英文表达(最多保留到小数点后两位)
String englishWord = Convert . numberToWord (money ) ;
Console . log ( "金额转英文表达:{}" , englishWord ) ; // EIGHTEEN AND CENTS EIGHTY EIGHT ONLY

double amount = 102389942.32D ;
// 数字转中文大写(例:壹仟,最多保留到小数点后两位) isUseTraditional => true
String traditionalChinese = Convert . numberToChinese (amount , true ) ;
// 数字转中文小写(例:一千) isUseTraditional => false
String nonTraditionalChinese = Convert . numberToChinese (amount , false ) ;
Console . log ( "数字转中文大写,传统:{};非传统:{}" , traditionalChinese , nonTraditionalChinese ) ; // 传统:壹亿零贰佰叁拾捌万玖仟玖佰肆拾贰点叁贰;非传统:一亿零二百三十八万九千九百四十二点三二

// 中文大写壹仟叁佰转成纯数字
Console . log ( "中文大写壹仟叁佰转成数字:{}" , Convert . chineseToNumber ( "壹仟叁佰" ) ) ; // 1300

// 数字简化 1000 => 1k; 10000 => 1w(最多保留到小数点后两位)
String simple = Convert . numberToSimple (amount ) ;
Console . log ( "{} 简化为:{}" , amount , simple ) ; // 10238.99w

convertTime(目标值,目标值时间单位,转换后的时间单位) 方法主要用于转换时长单位,比如一个很大的毫秒,我想获得这个毫秒数换算成多少天:



// 毫秒数
long ms = 100000000L ;
long msToDays = Convert . convertTime (ms , TimeUnit . MILLISECONDS , TimeUnit . DAYS ) ;
Console . log ( "{} 毫秒约等于 {} 天" , ms , msToDays ) ; // 100000000 毫秒约等于 1 天

原始类型和包装类型之间的转换



// Integer 包装类
Class <Integer > wrapClass = Integer .class ;

// Integer 去除包装类 => int
Class < ? > unWraped = Convert . unWrap (wrapClass ) ; // int
Console . log ( "Integer 包装类去包装化:{}" , unWraped ) ;

// 原始类
Class < ? > primitiveClass = long .class ;

// 将原始类型转换成包装类
Class < ? > wraped = Convert . wrap (primitiveClass ) ; // class java.lang.Long
Console . log ( "long 原始类包装化:{}" , wraped ) ;

DateUtil  DateTime 日期时间工具类

对于  java.util.Date 对象是不是还停留在被  Thu Nov dd HH:mm:ss CST yyyy 支配的恐惧中?数字英文单词缩写的混杂让人看起来非常不舒服,如果你想将其转换成  yyyy-MM-dd / yyyy-MM-dd HH:mm:ss 时间格式字符串,你是不是得先  new 一个  SimpleDateFormat,通过  pattern 参数进行初始化格式化器,时间格式不熟练的可能还要百度一下,甚是麻烦。

为了便捷, Hutool 工具使用了一个  DateTime 类来替代之,继承自  Date ,重写了  toString() 方法,直接放回  yyyy-MM-dd HH:mm:ss 形式的字符串,方便在输出时的调用(例如日志记录等),提供了众多便捷的方法对日期对象操作。

代码实例:



// 计时器,计算被其包裹的代码片段执行时间
final TimeInterval timeInterval = DateUtil . timer ( ) ;

// 根据 birthday 计算现在的年龄
String dateStr = "2000年05月26日" ;
Date birthday = Convert . toDate (dateStr ) ;
// 可以通过 DatePattern 指定 dateStr 日期时间格式进行解析,如果没有第二个参数,则会自动寻找合适的格式(支持多种格式)进行解析
// DateTime dateTime = new DateTime(dateStr, DatePattern.CHINESE_DATE_PATTERN);
int age = DateUtil . ageOfNow (birthday ) ; // 或 DateUtil.ageOfNow(dateTime);
Console . log ( "{} 出生的小伙子,如今已经 {} 岁了!" , dateStr , age ) ;

// 获取当前时间,格式:yyyy-MM-dd HH:mm:ss => DateTime 类型
Date currentDate = DateUtil . date ( ) ; // 2021-11-02 08:57:54
// 等价于 DateTime currentDateTime = new DateTime();
// 不同于 new Date() => Tue Nov 02 08:57:54 CST 2021
Console . log ( "DateUtil.date() 得到当前时间(yyyy-MM-dd HH:mm:ss):" , currentDate ) ;

// 将特殊的日期字符串转换为 DateTime 对象
String strDate2 = "2021年11月02日 12时03分29秒" ;
// 根据格式化模版将字符串日期转换为 Date 对象
Console . log ( "Use DateUtil.parse() method convert to Date: {}" , DateUtil . parse (strDate2 , "yyyy年MM月dd日 HH时mm分ss秒" ) ) ; // 2021-11-02 12:03:29
// 等价于 new DateTime(strDate2);

// 方式一:当前毫秒数转换为 DateTime 时间,格式:yyyy-MM-dd HH:mm:ss
Date msToDateTime1 = DateUtil . date (Calendar . getInstance ( ) ) ; // 2021-11-02 08:57:54
Console . log ( "当前毫秒数转换为 DateTime 时间,方式一:" , msToDateTime1 ) ;

// 方式二:当前毫秒数转换成 DateTime 时间,格式:yyyy-MM-dd HH:mm:ss
Date msToDateTime2 = DateUtil . date (System . currentTimeMillis ( ) ) ; // 2021-11-02 08:57:54
Console . log ( "当前毫秒数转换为 DateTime 时间,方式二:" , msToDateTime2 ) ;

// 当前日期字符串,格式:yyyy-MM-dd
String today = DateUtil . today ( ) ; // 2021-11-02
Console . log ( "当前日期字符串,格式:yyyy-MM-dd:{}" , today ) ;

// 将 Date 对象格式化为日期字符串,格式:yyyy-MM-dd
String formatDateStr = DateUtil . format ( new Date ( ) , "yyyy-MM-dd" ) ;
Console . log ( "Use DateUtil.format() method convert to Date: {}" , formatDateStr ) ;

// 获取日期时间(DateTime)的 Time 字符串,格式:HH:mm:ss
String formatTimeStr = DateUtil . formatTime ( new DateTime ( ) ) ;
Console . log ( "Use DateUtil.formatTime() method only covert Date to HH:mm:ss:{}" , formatTimeStr ) ;

// 星座(zodiac sign)
String zodiac = DateUtil . getZodiac (DateUtil . month (birthday ) , ( (int ) DateUtil . betweenDay (DateUtil . beginOfMonth (birthday ) , birthday , false ) ) ) ;
// 属相(chinese zodiac)
String chineseZodiac = DateUtil . getChineseZodiac (DateUtil . year (birthday ) ) ;
Console . log ( "{} 生日的人,星座是:{},属 {} 的。" , birthday , zodiac , chineseZodiac ) ;

// 判断今年是不是平闰年
boolean isLeapYear = DateUtil . isLeapYear (DateUtil . year ( new Date ( ) ) ) ;
Console . log ( "{}年是闰年吗?{}" , DateUtil . year ( new Date ( ) ) , isLeapYear ) ;

// 得到一个美化过后的花费时间,即加上中文单位
String spendTimePretty = timeInterval . intervalPretty ( ) ;
// 运行时间转换为秒为单位
long sec = timeInterval . intervalSecond ( ) ;

// 返回花费时间,并重置开始时间
long spendTimeAndRestart = timeInterval . intervalRestart ( ) ;

Console . log ( "测试运行时间(无单位不美化):" , spendTimeAndRestart ) ;
Console . log ( "测试运行时间(有单位带美化):" , spendTimePretty ) ;
Console . log ( "测试运行时间,转换为秒:{}" , sec ) ;

获取指定天/周/月/季度/年的开始/结束时间,返回  DateTime,格式为: yyyy-MM-dd HH:mm:ss

DateTime beginOfDayTime 
= DateUtil
.
beginOfDay
(
new 
Date
(
)
)
;

Console . log ( "今天开始时间:{}" , beginOfDayTime ) ; // 2021-11-03 00:00:00

DateTime beginOfYearTime = DateUtil . beginOfYear ( new Date ( ) ) ;
Console . log ( "今年开始时间:{}" , beginOfYearTime ) ; // 2021-01-01 00:00:00

DateTime endOfYearTime = DateUtil . endOfYear ( new Date ( ) ) ;
Console . log ( "今年结束时间:{}" , endOfYearTime ) ; // 2021-12-31 23:59:59

日期时间偏移:即对某个日期增减分、小时、天等等



// 将当前时间增加半个小时
DateTime halfHourLater = DateUtil . offset (currentDate , DateField . MINUTE , 30 ) ;
// 等同于:DateUtil.offsetHour(currentDate, 30);
Console . log ( "当前时间是 {},半个小时后是:{}" , currentDate , halfHourLater ) ;
// 五天后的现在时间
DateTime fiveDaysFromNow = DateUtil . offsetDay (currentDate , 5 ) ;

Console . log ( "当前时间是 {},五天后是:{}" , currentDate , fiveDaysFromNow ) ;
// 针对当前时间,提供了更为简化的偏移方法
Console . log ( "昨天的现在是:{}" , DateUtil . yesterday ( ) ) ;
Console . log ( "明天的现在是:{}" , DateUtil . tomorrow ( ) ) ;
Console . log ( "上周天的现在是:{}" , DateUtil . lastWeek ( ) ) ;
Console . log ( "下周的现在是:{}" , DateUtil . nextWeek ( ) ) ;
Console . log ( "上个月的现在是:{}" , DateUtil . lastMonth ( ) ) ;
Console . log ( "下个月的现在是:{}" , DateUtil . nextMonth ( ) ) ;

计算两个时间的间隔



// 当前时间
DateTime currentDateTime = new DateTime ( ) ;

String dateTimeStrStart = "1949/10/01" ;
Date startTime = Convert . toDate (dateTimeStrStart ) ;
long betweenDays = DateUtil . between (startTime , new DateTime ( ) , DateUnit . DAY ) ;
Console . log ( "距离新中国成立,已经过了 {} 天" , betweenDays ) ;

// 下班时间(当天 17:00:00 )
Date getOffTime = DateUtil . offsetHour (DateUtil . beginOfDay (currentDateTime ) , 17 ) ;
Console . log ( "下班时间是:{}" , getOffTime ) ;
long distance = DateUtil . between (getOffTime , currentDateTime , DateUnit . SECOND , true ) ;

// 间隔时间设置为秒
Console . log ( "距离下班还剩 {} 秒" , distance ) ;
// 格式化间隔时间
Console . log ( "距离下班还剩 {} 精确到秒" , DateUtil . formatBetween (getOffTime , currentDateTime , BetweenFormatter .Level . SECOND ) ) ;

ObjectUtil 对象信息打印类

针对  Object 通用的工具类方法,不区分是  String 还是  Object 、 Array 还是  Collection。

代码实例:

判断  null /  blank string

final String blankStr 
= 
"   "
;

final String nullStr = null ;
final String dateStr = null ;

// isEmpty/isNull 只有为 null 才返回 true
System .out . println (ObjectUtil . isEmpty (blankStr ) ) ; // false
System .out . println (ObjectUtil . isEmpty (nullStr ) ) ; // true
System .out . println (ObjectUtil . isNull (nullStr ) ) ; // true
System .out . println (ObjectUtil . isNull (blankStr ) ) ; // false
//java学习交流:737251827  进入可领取学习资源及对十年开发经验大佬提问,免费解答!
// null/空格字符串都是 blank
System .out . println (ObjectUtil . defaultIfBlank (blankStr , "目标字符串为空,我是默认" ) ) ; // 走 defaultValue
System .out . println (ObjectUtil . defaultIfBlank (nullStr , "目标字符串为空,我是默认" ) ) ; // 走 defaultValue

// 此处判断如果dateStr为null,则调用`Instant.now()`,不为null则执行`DateUtil.parse`
System .out . println (ObjectUtil . defaultIfNull (dateStr , ( ) - > DateUtil . parse (dateStr , DatePattern . NORM_DATETIME_PATTERN ) . toInstant ( ) , Instant . now ( ) ) ) ;

System .out . println (ObjectUtil . defaultIfNull (nullStr , "目标字符串为 null ,我是默认" ) ) ; // 走 defaultValue
System .out . println (ObjectUtil . defaultIfNull (blankStr , "目标字符串为 null ,我是默认" ) ) ; // blankStr

注意: ObjectUtil.isNull() 方法不能判断对象中字段为空的情况,如果需要检查Bean对象中字段是否全空,需使用  BeanUtil.isEmpty() 方法进行判定。


判断两个对象是否相等,等价于  Objects.equals() 方法



ObjectUtil . equals (nullStr , dateStr ) ; // true
ObjectUtil . equals ( "HUALIE" , "HUALEI" ) ; // true

// 等价于
Objects . equals (nullStr , dateStr ) ; // true

计算对象长度



int [ ] array = new int [ ] { 1 , 2 , 3 , 4 , 5 } ;
// 计算数组长度
int length = ObjectUtil . length (array ) ; // 5

Map <String , String > map = new HashMap < > ( ) ;
map . put ( "a" , "a1" ) ;
map . put ( "b" , "b1" ) ;
map . put ( "c" , "c1" ) ;

// 计算 Map 大小
length = ObjectUtil . length (map ) ; // 3

如果是字符串调用其  length() 方法,集合类调用其  size() 方法,数组调用其 length 属性,其他可遍历对象遍历计算长度。

StrUtil 处理字符串工具

↑ 和这个类类似,但是相较于  StringUtils 这个类写起来更短,更能偷懒 [狗头],类中常用的方法有  isBlank()、 isNotBlank()、 isEmpty()、 isNotEmpty() 主要用于对字符串的判空,这里就不赘述了。

代码实例:



// 去除前缀
String [ ] tableNames = { "tb_user" , "t_mall" , "province" , "t_capital" , "tb_task" } ;
for (int i = 0 ; i < tableNames .length ; i ++ ) {
    if (StrUtil . containsAnyIgnoreCase (tableNames [i ] , "tb_" , "t_" ) ) {
        // 去除前缀忽略大小写
       tableNames [i ] = StrUtil . removePrefixIgnoreCase (tableNames [i ] , "tb_" ) ;
        // 去除前缀忽略大小写
       tableNames [i ] = StrUtil . removePrefixIgnoreCase (tableNames [i ] , "t_" ) ;
    }
}
Console . log ( "移除表名前缀后:{}" , (Object ) tableNames ) ; // [user, mall, province, capital, task]

// 去除后缀
String fileName = StrUtil . removeSuffix ( "HUALEI.png" , ".png" ) ;
Console . log ( "去除文件.扩展名后:{}" , fileName ) ; // HUALEI

// 字符创常量,包括点、空字符串、换行符,还有一些 HTML 中的转义字符
System .out . println (StrUtil . AT . concat ( "HUALEI" ) . concat (StrUtil . DOT ) . concat (StrUtil . LF ) ) ; // @HUALEI.

// 使用字符串模板代替字符串拼接
String template = "{}爱{},我爱你,蜜雪冰城{}" ;
String str = StrUtil . format (template , "你" , "我" , "甜蜜蜜" ) ; // 你爱我,我爱你,蜜雪冰城甜蜜蜜

CollUtil | CollStreamUtil 集合处理工具类

这两个类主要封装的是对数组、列表等集合类的操作方法,集合在开发中占很大一部分,必须重点掌握,以提高我们的开发效率。

代码实例:

模拟数据库排序分页,返回一个  PageResult



List <Fruit > fruits = fruitMapper . selectList (Wrappers . emptyWrapper ( ) ) ;

// 总记录数
long totalCount = fruits . size ( ) ;
// 当前页
int currentPage = 1 ;
// 每页记录数
int pageSize = 10 ;

// 当前页索引,从 0 开始,表示第一页
int pageNo = currentPage - 1 ;

// 默认分页列表
List <Fruit > defaultPageList = CollUtil . page (pageNo , pageSize , fruits ) ;

// 按照记录更新时间进行排序分页列表
List <Fruit > orderPageList = CollUtil . sortPageAll (pageNo , pageSize , Comparator . comparing (Fruit : :getUpdateTime ) , fruits ) ;

// 重新用分页参数及记录列表组装 PageResult 分页结果对象
PageResult pageResult = new PageResult (orderPageList , totalCount , pageSize , currentPage ) ) ;

System .out . println ( "当前页数:" + pageResult . getCurrPage ( ) ) ;
System .out . println ( "每页记录数:" + pageResult . getPageSize ( ) ) ;
System .out . println ( "总记录数:" + pageResult . getTotalCount ( ) ) ;
System .out . println ( "总页数:" + pageResult . getTotalPage ( ) ) ;
// 当前页记录列表
pageResult . getList ( ) . forEach (System .out : :println ) ;

获取表头别名映射



// 字段名列表
List <String > headerNameList = new ArrayList < > ( ) ;

// 使用反射工具获取全部表头名
for (Field field : ReflectUtil . getFields (ProvinceExcelVO .class ) ) {
    if ( !StrUtil . equals (field . getName ( ) , "serialVersionUID" ) ) {
       headerNameList . add (field . getName ( ) ) ;
    }
}
// 表头别名列表
List <String > aliasList = CollUtil . newArrayList ( "省份名称" , "简称" , "面积(km²)" , "人口数量(万)" , "著名景点" , "邮政编码" , "省会城市" , "别称" , "气候类型" , "车牌号" ) ;

// 一一对应,形成表头别名映射
Map <String , String > headerAliasMap = CollUtil . zip (fieldNameList , aliasList ) ;

建立省名和省份对象之间的  Map


// 省份表中所有省份信息

List <Province > provinces = provinceMapper . selectList (Wrappers . emptyWrapper ( ) ) ;

// 使用 CollStreamUtil 集合流工具,一行代码解决
Map <String , Province > provinceMap = CollStreamUtil . toIdentityMap (provinces , Province : :getProvince ) ;

// 等价于
Map <String , List <Province >> provinceMap =
       provinces . stream ( )
                . collect (Collectors . toMap (Province : :getProvince , Arrays : :asList ) ) ;

// 又等价于,结合 Convert 方法二:
Map <String , List <Province >> provinceMap =
       provinces . stream ( )
                . collect (Collectors . toMap (Province : :getProvince , p - > Convert . toList (Province .class , p ) ) ) ;

// 获取江西省省份信息
Console . log ( "江西省省份信息为:{}" , provinceMap . get ( "江西省" ) ) ;

将所有省份按照主键  pid 进行分组



Map <Integer , List <Province >> groupByKey = CollStreamUtil . groupByKey (CollUtil . unionAll (provinces , provinces ) , Province : :getPid ) ;

// 等价于
Map <Integer , List <Province >> groupByKey = CollUtil . unionAll (provinces , provinces ) . stream ( )
                . collect (Collectors . groupingBy (Province : :getPid , Collectors . toList ( ) ) ) ;

提取省份信息列表中省份名

        

List <String > provinceNameList = CollStreamUtil . toList (provinces , Province : :getProvince ) ;

// 等价于
List <String > provinceNameList = provinces . stream ( )
        . map (Province : :getProvince )
        . collect (Collectors . toList ( ) ) ;

两个  map 根据  key 进行合并( merge)操作,最终结果期望为:( key:  pid,  value:  province(省份名) + "-" + abbr(省份简称))



// (key: pid, value: province)            
Map <Integer , String > pidToProvince = CollStreamUtil . toMap (provinces , Province : :getPid , Province : :getProvince ) ;

// 等价于
Map <Integer , String > pidToProvince =
       provinces . stream ( )
                . collect (Collectors . toMap (Province : :getPid , Province : :getProvince ) ) ;
               
// (key: pid, value: abbr)      
Map <Integer , String > pidToAbbr = CollStreamUtil . toMap (provinces , Province : :getPid , Province : :getAbbr ) ;

// 等价于
Map <Integer , String > pidToProvince =
       provinces . stream ( )
                . collect (Collectors . toMap (Province : :getPid , Province : :getAbbr ) ) ;

// 根据 key 合并 Map,key 相同则走 merge 规则
Map <Integer , String > mergeResult = CollStreamUtil . merge (pidToProvince , pidToAbbr , (province , abbr ) - > province + "-" + abbr ) ;

RandomUtil 随机工具

RandomUtil 工具类主要是对  Random 对象的封装,用于产生随机数/列表,虽然是伪随机数,但是对于大多数使用场景还是够用的。

代码实例:



// 生成指定范围内的随机整数
for (int i = 0 ; i < 10 ; i ++ ) {
   System .out . println (RandomUtil . randomInt ( 0 , 100 ) ) ;
}

List <String > randomList = new ArrayList < > ( ) ;
// 生成随机字符串(只包含数字和字符)
for (int i = 0 ; i < 10 ; i ++ ) {
   randomList . add (RandomUtil . randomString ( 5 ) ) ;
}

// 从指定列表中随机取 5 个数
List <Integer > eleList = RandomUtil . randomEleList (Arrays . asList ( 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ) , 5 ) ;

// 随机从字符串列表中取出 5 个,不重复(取出的个数不能超过列表的大小)
Set <String > eleSet = RandomUtil . randomEleSet (randomList , 5 ) ;

// 权重随机生成器,传入带权重的对象,然后根据权重随机获取对象
WeightRandom weightRandom = RandomUtil . weightRandom ( new WeightRandom .WeightObj [ ] { new WeightRandom .WeightObj ( "HUA" , 60 ) , new WeightRandom .WeightObj ( "L" , 10 ) , new WeightRandom .WeightObj ( "EI" , 30 ) } ) ;

// 随机取 10 次,"HUA" 字符串出现的次数是最多的
for (int i = 0 ; i < 10 ; i ++ ) {
   System .out . println (weightRandom . next ( ) ) ;
}

ExcelUtil Excel 操作工具类

该类是对  Apache 的  POI 库的二次封装,便捷了对  MS Office 文档操作,使用该类时,需要用户执行导入  poi-ooxml 依赖,这个包会自动关联引入  poi 包,可以很好的支持  Office2007+ 的文档格式。

注意

开始使用前,需导入依赖:


<dependency
>

    <groupId >org .apache .poi < /groupId >
    <artifactId >poi -ooxml < /artifactId >
    <version >$ {poi .version } < /version >
< /dependency >

未引入使用其中的工具方法,会报错:

You need to add dependency of 'poi-ooxml' to your project, and version >= 4.1.2

代码实例:


// 写入 Excel 中的数据源

List <Province > provinces = provinceMapper . selectList (Wrappers . emptyWrapper ( ) ) ;

// 写出文件路径
String inputPath = "D:/桌面/导出省份信息.xlsx" ;
// 通过工具类创建一个 Writer 写入对象
ExcelWriter excelWriter = ExcelUtil . getWriter (inputPath , "省份信息表" ) ;

// 自定义表头名(方法一)
excelWriter . addHeaderAlias ( "pid" , "省份ID" ) ;
excelWriter . addHeaderAlias ( "province" , "省份" ) ;
excelWriter . addHeaderAlias ( "abbr" , "简称" ) ;
excelWriter . addHeaderAlias ( "area" , "面积(km²)" ) ;
excelWriter . addHeaderAlias ( "population" , "人口数量(万)" ) ;
excelWriter . addHeaderAlias ( "attraction" , "著名景点" ) ;
excelWriter . addHeaderAlias ( "capital" , "省会" ) ;

// 自定义表头名(方法二)
Map <String , String > headerAlias = new LinkedHashMap < > ( 7 ) ;
//java学习交流:737251827  进入可领取学习资源及对十年开发经验大佬提问,免费解答!
for (Field field : ReflectUtil . getFields (Province .class ) ) {
   String name = field . getName ( ) ;
   String alias ;
    switch (name ) {
        case "pid" :
           alias = "省份ID" ;
            break ;
        case "province" :
           alias = "省份" ;
            break ;
        case "abbr" :
           alias = "简称" ;
            break ;
        case "area" :
           alias = "面积(km²)" ;
            break ;
        case "population" :
           alias = "人口数量(万)" ;
            break ;
        case "attraction" :
           alias = "著名景点" ;
            break ;
        case "capital" :
           alias = "省会" ;
            break ;
        default :
           alias = null ;
    }
    if (ObjectUtil . isNotEmpty (alias ) ) {
       headerAlias . put (field . getName ( ) , alias ) ;
    }
}

// 使用无序的 HashMap 入参表头也跟着无序,需使用 LinkedHashMap ,保证有序
excelWriter . setHeaderAlias (headerAlias ) ;

// 写出数据源到 Excel 当中,使用默认样式,强制输出标题
excelWriter . write (provinces , true ) ;

// 关闭 writer ,释放内存
excelWriter . close ( ) ;

结尾

撰文不易,欢迎大家点赞、评论,你的关注、点赞是我坚持的不懈动力,感谢大家能够看到这里!Peace & Love。


 



来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70010294/viewspace-2848468/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2021-11-19

  • 博文量
    199
  • 访问量
    86383