简介与安装
简介
Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。
Hutool中的工具方法来自每个用户的精雕细琢,它涵盖了Java开发底层代码中的方方面面,它既是大型项目开发中解决小问题的利器,也是小型项目中的效率担当;
Hutool是项目中“util”包友好的替代,它节省了开发人员对项目中公用类和公用工具方法的封装时间,使开发专注于业务,同时可以最大限度的避免封装不完善带来的bug。
Hutool名称的由来
Hutool = Hu + tool,是原公司项目底层代码剥离后的开源库,“Hu”是公司名称的表示,tool表示工具。Hutool谐音“糊涂”,一方面简洁易懂,一方面寓意“难得糊涂”。
Hutool如何改变我们的coding方式
Hutool的目标是使用一个工具方法代替一段复杂代码,从而最大限度的避免“复制粘贴”代码的问题,彻底改变我们写代码的方式。
以计算MD5为例:
Hutool的存在就是为了减少代码搜索成本,避免网络上参差不齐的代码出现导致的bug。
上述摘自HuTool官网
安装
在Maven项目中
在项目的pom.xml的dependencies中加入以下内容:
|
1
2
3
4
5
|
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.5.8</version>
</dependency>
|
非Maven项目中
点击以下任一链接,下载hutool-all-X.X.X.jar即可:
Maven中央库1
Maven中央库2
注意 Hutool 5.x支持JDK8+,对Android平台没有测试,不能保证所有工具类或工具方法可用。 如果你的项目使用JDK7,请使用Hutool 4.x版本
常用方法
本文的所有代码均已上传GitHub,HuTool学习
类型转换
类型转换的工具类为Convert
转为字符串
|
1
2
3
4
5
6
7
8
9
10
|
// int类型转换
int aInt = 1023;
String aStr = Convert.toStr(aInt);
// aStr结果为1023
System.out.println(aStr);
// 数组进行转换
int[] bArray = {1,2,3,4,5};
String bStr = Convert.toStr(bArray);
// bStr结果为[1, 2, 3, 4, 5]
System.out.println(bStr);
|
转为指定类型数组
|
1
2
3
4
5
6
7
8
9
|
String[] strArray = { "1", "0", "2", "3" };
//结果为Integer数组
Integer[] intArray = Convert.toIntArray(strArray);
System.out.println(Convert.toStr(intArray));
Integer[] intArray2 = {1,0,2,3};
//结果为String数组
String[] strArray2 = Convert.toStrArray(intArray2);
System.out.println(Convert.toStr(strArray2));
|
转换为Date日期对象
|
1
2
3
4
|
String date = "2000-10-23";
//结果为Date日期对象
Date value = Convert.toDate(date);
System.out.println(value);
|
转化为List集合
|
1
2
3
4
5
6
|
Object[] objectArray = {"lolly1023","lolly",1023};
List<?> list = Convert.convert(List.class, objectArray);
System.out.println(list);
// 4.1.11版本之后可使用toList
List<?> list2 = Convert.toList(objectArray);
System.out.println(list2);
|
日期时间
日期时间的工具类为DateUtil
多种获取日期的方式
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
// 获取当前时间的Date对象
Date nowDate = DateUtil.date();
System.out.println(nowDate);
// 使用Calendar获取当前时间的Date对象
Date nowDate2 = DateUtil.date(Calendar.getInstance());
System.out.println(nowDate2);
// 使用当前时间戳获取当前时间的Date对象
Date nowDate3 = DateUtil.date(System.currentTimeMillis());
System.out.println(nowDate3);
// 使用工具类获取当前时间的字符串,格式为:yyyy-MM-dd HH:mm:ss
String nowDateStr = DateUtil.now();
System.out.println(nowDateStr);
// 使用工具类获取当前时间的字符串,格式为:yyyy-MM-dd
String todayDateStr= DateUtil.today();
System.out.println(todayDateStr);
|
输出样式为:
2021-02-19 21:04:12
2021-02-19 21:04:12
2021-02-19 21:04:12
2021-02-19 21:04:12
2021-02-19
字符串转换为Date对象
字符串转为Date对象使用到了DateUtil工具类中的parse方法,该方法会自动识别一些日期的常用格式,例如:
- yyyy-MM-dd HH:mm:ss.SSS
- yyyy-MM-dd HH:mm:ss
- yyyy-MM-dd HH:mm
- yyyy-MM-dd
- HH:mm:ss
|
1
2
3
4
5
6
7
8
9
10
|
// 字符串转为Date对象
String dateStr = "2000-10-23 12:30";
Date date = DateUtil.parse(dateStr);
// 输出2000-10-23 12:30:00
System.out.println(date);
// 也可以在转的时候指定格式
Date date2 = DateUtil.parse(dateStr,"yyyy-MM-dd");
// 输出2000-10-23 00:00:00
System.out.println(date2);
|
格式化Date对象
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
//格式化Date日期对象
Date date4 = DateUtil.date();
String format = DateUtil.format(date4, "yyyy年MM月dd日");
// 输出为2021年02月19日
System.out.println(format);
String formatDate = DateUtil.formatDate(date4);
// 常用格式化,输出为2021-02-19
System.out.println(formatDate);
String formatDateTime = DateUtil.formatDateTime(date4);
// 精确到秒,结果为2021-02-19 21:16:09
System.out.println(formatDateTime);
String formatTime = DateUtil.formatTime(date4);
// 只保留时分秒,结果为21:16:09
System.out.println(formatTime);
|
获取Date对象的年月日
|
1
2
3
4
5
6
7
8
9
10
11
12
|
// 获取Date对象的年月日
Date date5 = DateUtil.date();
// 获取年,结果为2021
System.out.println(DateUtil.year(date5));
// 获取月,结果为1(从0开始计数,0则为一月)
System.out.println(DateUtil.month(date5));
// 获取日(在本年)
System.out.println(DateUtil.dayOfYear(date5));
// 获取日(在本月)
System.out.println(DateUtil.dayOfMonth(date5));
// 获取日(在本周)
System.out.println(DateUtil.dayOfWeek(date5));
|
开始和结束日期
用于计算开始时间和结束时间,有每天的,每月的,等等
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
Date date3 = DateUtil.date();
//一天的开始,结果:2021-02-19 00:00:00
Date beginOfDay = DateUtil.beginOfDay(date3);
System.out.println(beginOfDay);
//一天的结束,结果:2021-02-19 23:59:59
Date endOfDay = DateUtil.endOfDay(date3);
System.out.println(endOfDay);
//一月的开始,结果:2021-02-01 00:00:00
Date beginOfMonth = DateUtil.beginOfMonth(date3);
System.out.println(beginOfMonth);
//一月的结束,结果:2021-02-28 23:59:59
Date endOfMonth = DateUtil.endOfMonth(date3);
System.out.println(endOfMonth);
|
日期时间的偏移
对日期的减少或者添加,可以对时分秒天周月等进行更改
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
String dateStr2 = "2000-10-23 12:30";
Date date6 = DateUtil.parse(dateStr2);
// 偏移10天
DateTime newDate = DateUtil.offsetDay(date, 10);
// 结果为2000-11-02 12:30:00
System.out.println(newDate);
// 偏移-10天
DateTime newDate2 = DateUtil.offsetDay(date, -10);
// 结果为2000-10-13 12:30:00
System.out.println(newDate2);
/**常用的偏移还有
* 月份 :DateUtil.offsetMonth(newDate2, offset)
* 周:DateUtil.offsetWeek(newDate2, offset)
*/
// 对比这种偏移,还有一种较简单的偏移方法
//昨天
System.out.println(DateUtil.yesterday());
//明天
System.out.println(DateUtil.tomorrow());
//上周
System.out.println(DateUtil.lastWeek());
//下周
System.out.println(DateUtil.nextWeek());
//上个月
System.out.println(DateUtil.lastMonth());
//下个月
System.out.println(DateUtil.nextMonth());
|
日期时间差
用于计算两个日期直接的时间差
|
1
2
3
4
5
6
7
8
|
String dateStr3 = "2000-10-23 12:30:00";
Date date7 = DateUtil.parse(dateStr3);
Date date8 = DateUtil.date();
// 计算2000-10-23距今多久:7424天
long betweenDay = DateUtil.between(date7, date8, DateUnit.DAY);
System.out.println(betweenDay);
|
计时器
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
TimeInterval timer = DateUtil.timer();
try {
// 模拟耗时操作
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//花费毫秒数
System.out.println(timer.interval());
//返回花费时间,并重置开始时间
System.out.println(timer.intervalRestart());
//花费分钟数
System.out.println(timer.intervalMinute());
|
星座与属相
这个功能还是挺出乎意料的,没想到还有这种
|
1
2
3
4
5
6
|
// "天秤座"
String zodiac = DateUtil.getZodiac(Month.OCTOBER.getValue(), 23);
System.out.println(zodiac);
// "龙"
String chineseZodiac = DateUtil.getChineseZodiac(2000);
System.out.println(chineseZodiac);
|
年龄与闰年判断
不得不说,这个工具类小玩意还挺多
|
1
2
3
4
5
|
//年龄
System.out.println(DateUtil.ageOfNow("2000-10-23"));
//是否闰年
System.out.println(DateUtil.isLeapYear(2000));
|
IO流相关
文件的拷贝
|
1
2
3
4
5
6
7
8
9
|
// 文件的拷贝
BufferedInputStream in = FileUtil.getInputStream("d:/桌面/HuTool学习.md");
BufferedOutputStream out = FileUtil.getOutputStream("d:/桌面/HuTool学习复制.md");
long copySize = IoUtil.copy(in, out, IoUtil.DEFAULT_BUFFER_SIZE);
// 拷贝文件的大小
System.out.println(copySize);
System.out.println("拷贝成功");
in.close();
out.close();
|
文件类型判断
用于文件类型的判断,返回值为文件的类型
|
1
2
3
4
|
File file = FileUtil.file("d:/桌面/HuTool学习.md");
String type = FileTypeUtil.getType(file);
//输出的是文件的格式
Console.log(type);
|
文件监听
在以前,我们需要监听文件的变化:创建修改删除等,需要进行遍历来定时检查文件,效率很低,性能很差,所以有了这个工具类。
监听指定事件
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
File file2 = FileUtil.file("example.properties");
//这里只监听文件或目录的修改事件
WatchMonitor watchMonitor = WatchMonitor.create(file2, WatchMonitor.ENTRY_MODIFY);
watchMonitor.setWatcher(new Watcher(){
@Override
public void onCreate(WatchEvent<?> event, Path currentPath) {
Object obj = event.context();
Console.log("创建:{}-> {}", currentPath, obj);
}
@Override
public void onModify(WatchEvent<?> event, Path currentPath) {
Object obj = event.context();
Console.log("修改:{}-> {}", currentPath, obj);
}
@Override
public void onDelete(WatchEvent<?> event, Path currentPath) {
Object obj = event.context();
Console.log("删除:{}-> {}", currentPath, obj);
}
@Override
public void onOverflow(WatchEvent<?> event, Path currentPath) {
Object obj = event.context();
Console.log("Overflow:{}-> {}", currentPath, obj);
}
});
//设置监听目录的最大深入,目录层级大于制定层级的变更将不被监听,默认只监听当前层级目录
watchMonitor.setMaxDepth(3);
//启动监听
watchMonitor.start();
|
监听全部事件
|
1
2
3
4
5
6
|
WatchMonitor.createAll(file, new SimpleWatcher(){
@Override
public void onModify(WatchEvent<?> event, Path currentPath) {
Console.log("EVENT modify");
}
}).start();
|
文件的读取
|
1
2
3
4
|
//默认UTF-8编码,可以在构造中传入第二个参数做为编码
FileReader fileReader = new FileReader("d:/桌面/HuTool测试.txt");
String result = fileReader.readString();
System.out.println(result);
|
文件的写入
|
1
2
|
FileWriter writer = new FileWriter("d:/桌面/HuTool测 试.txt");
writer.write("添加文本",true);
|
文件追加
主要用于类似日志这种(此类只有在写入文件的时候打开文件,写入结束之后,此类不需要关闭)
|
1
2
3
4
5
6
7
8
|
File file = new File("d:/桌面/HuTool测试.txt");
FileAppender appender = new FileAppender(file, 16, true);
appender.append("lolly1023");
appender.append("追加");
appender.append("成功");
appender.flush();
appender.toString();
|
文件跟随
有时候需要启动线程来“监控”文件的变化,类似于Linux下的tail -f命令
|
1
2
|
Tailer tailer = new Tailer(FileUtil.file("d:/桌面/test.log"), Tailer.CONSOLE_HANDLER, 2);
tailer.start();
|
实时打印文件变化的类
|
1
2
3
4
5
6
7
8
9
10
11
12
|
/**
* 命令行打印的行处理器
*
* @author looly
* @since 4.5.2
*/
public static class ConsoleLineHandler implements LineHandler {
@Override
public void handle(String line) {
Console.log(line);
}
}
|
该方法会阻塞线程
文件名与扩展名
获取文件名
|
1
2
3
4
5
|
File file = FileUtil.file("d:/桌面/HuTool学习.md");
// HuTool学习.md
String name = FileNameUtil.getName(file);
System.out.println(name);
|
单独获取主文件名与扩展名
|
1
2
3
4
5
6
7
8
|
File file1 = FileUtil.file("d:/桌面/HuTool学习.md");
// "HuTool学习"
String name1 = FileNameUtil.mainName(file1);
System.out.println(name1);
// "md"
String name2 = FileNameUtil.extName(file1);
System.out.println(name2);
|
工具类
字符串工具
判断是否为空
给定指定字符串,如果是空,则返回true,使用到hasBlank和hasEmpty方法。hasEmpty只判断是否为null或者是空字符串,hasBlank会把不可见的字符也算为空。
|
1
2
3
4
5
|
String nullStr = null;
// true
System.out.println(StrUtil.hasBlank(nullStr));
// true
System.out.println(StrUtil.hasEmpty(nullStr));
|
删除前后缀
removePrefix为删除字符串前缀,removeSuffix为删除字符串后缀,经常用于去文件扩展名。
|
1
2
3
4
5
6
|
String fileName = StrUtil.removeSuffix("HuTool学习.md", ".md");
// HuTool学习
System.out.println(fileName);
String fileName1 = StrUtil.removePrefix("HuTool学习.md", "HuTool学习.");
// md
System.out.println(fileName1);
|
截取字符串
在String中就有截取字符串的方法,但是时常会越界,在这个工具类中,该方法会自动判断,支持负数,(与python相同),第二个位置与第一个位置搞反了的话,也会自动识别更改。
|
1
2
3
4
5
6
7
8
9
10
11
|
String str = "lolly1023";
String strSub1 = StrUtil.sub(str, 0, 5);
// lolly
System.out.println(strSub1);
String strSub2 = StrUtil.sub(str, 0, -4);
// lolly
System.out.println(strSub2);
String strSub3 = StrUtil.sub(str, 5, 0);
// lolly
System.out.println(strSub3);
|
格式化字符串
使用{}进行占位即可,然后使用format方法进行格式化
|
1
2
3
4
5
|
// 使用{}占位
String template = "{}+{}=2";
// 1+1=2
String str1 = StrUtil.format(template, "1", "1");
System.out.println(str1);
|
16进制工具
16进制的转换
|
1
2
3
4
5
6
7
8
9
|
String str = "测试16进制转换";
String hex = HexUtil.encodeHexStr(str, CharsetUtil.CHARSET_UTF_8);
// e6b58be8af953136e8bf9be588b6e8bdace68da2
System.out.println(hex);
String decodedStr = HexUtil.decodeHexStr(hex);
// 测试16进制转换,解码后与str相同
System.out.println(decodedStr);
|
URL工具
标准化URL链接
对于不带http://头的地址做简单补全。
|
1
2
3
4
5
6
7
8
|
String url = "http://www.hutool.cn//aaa/bbb";
// 结果为:http://www.hutool.cn/aaa/bbb
String normalize = URLUtil.normalize(url);
System.out.println(normalize);
url = "http://www.hutool.cn//aaa/\\\\bbb?a=1&b=2";
// 结果为:http://www.hutool.cn/aaa/bbb?a=1&b=2
normalize = URLUtil.normalize(url);
System.out.println(normalize);
|
XML工具
读取XML
读取XML分为两个方法:
-
XmlUtil.readXML读取XML文件 -
XmlUtil.parseXml解析XML字符串为Document对象
写XML
XmlUtil.toStr 将XML文档转换为String
XmlUtil.toFile 将XML文档写入到文件
创建XML
XmlUtil.createXml 创建XML文档, 创建的XML默认是utf8编码,修改编码的过程是在toStr和toFile方法里,既XML在转为文本的时候才定义编码。
XML操作
通过以下工具方法,可以完成基本的节点读取操作。
XmlUtil.cleanInvalid 除XML文本中的无效字符
XmlUtil.getElements 根据节点名获得子节点列表
XmlUtil.getElement 根据节点名获得第一个子节点
XmlUtil.elementText 根据节点名获得第一个子节点
XmlUtil.transElements 将NodeList转换为Element列表
XML与对象转换
writeObjectAsXml 将可序列化的对象转换为XML写入文件,已经存在的文件将被覆盖。
readObjectFromXml 从XML中读取对象。
注意 这两个方法严重依赖JDK的
XMLEncoder和XMLDecoder,生成和解析必须成对存在(遵循固定格式),普通的XML转Bean会报错。
Xpath操作
更多Xpath操作:点击此处
举例xml文件
|
1
2
3
4
5
6
7
8
9
|
<?xml version="1.0" encoding="utf-8"?>
<returnsms>
<returnstatus>Success(成功)</returnstatus>
<message>ok</message>
<remainpoint>1490</remainpoint>
<taskID>885</taskID>
<successCounts>1</successCounts>
</returnsms>
|
java代码
|
1
2
3
4
5
|
File xmlFile = new File("/Study/HuToolTest/src/main/java/com/rj/bd/HuToolTest/UTilTest/URLUtil/Test.xml");
Document docResult=XmlUtil.readXML(xmlFile);
Object value = XmlUtil.getByXPath("//returnsms/message", docResult, XPathConstants.STRING);
// ok
System.out.println(value.toString());
|
对象工具 两个对象是否相等
需要满足:
obj1 == null && obj2 == null
obj1.equals(obj2)
才会返回true
|
1
2
3
4
|
String string1 = "1";
Integer integer1 = 1;
// false
System.out.println(ObjectUtil.equal(string1, integer1));
|
计算对象长度
其实本质就是调用不同对象的计算长度方法,支持的类型有:
- CharSequence
- Collection
- Map
- Iterator
- Enumeration
- Array
|
1
2
3
|
List<Integer> list = new ArrayList<Integer>();
// 0
System.out.println(ObjectUtil.length(list));
|
判断是否包含元素
即为判断对象中是否包含元素
|
1
2
3
4
|
List<Integer> list1 = new ArrayList<Integer>();
list1.add(0);
// true
System.out.println(ObjectUtil.contains(list1, 0));
|
判断是否为空
|
1
2
3
4
5
|
List<Integer> list2 = new ArrayList<Integer>();
// false
System.out.println(ObjectUtil.isNull(list2));
// true
System.out.println(ObjectUtil.isNotNull(list2));
|
克隆
ObjectUtil.clone克隆对象,如果对象实现Cloneable接口,调用其clone方法,如果实现Serializable接口,执行深度克隆,否则返回null。
ObjectUtil.cloneIfPossible 返回克隆后的对象,如果克隆失败,返回原对象
ObjectUtil.cloneByStream 序列化后拷贝流的方式克隆,对象必须实现Serializable接口
序列化与反序列化 serialize 序列化,调用JDK序列化unserialize 反序列化,调用JDK 判断基本类型
如果该对象是基本类型,则返回true,反之返回false。
|
1
2
3
|
int i = 0;
// true
System.out.println(ObjectUtil.isBasicType(i));
|
反射 获取某类的全部方法
|
1
2
|
// 获取类中的全部方法
Method[] methods = ReflectUtil.getMethods(Test.class);
|
获取某类的某个方法
