有了它,Java語法也可以變得甜甜的

簡介

Hutool是一個小而全的Java工具類庫,通過靜態方法封裝,降低相關API的學習成本,提高工作效率,使Java擁有函數式語言般的優雅,讓Java語言也可以“甜甜的”。

Hutool中的工具方法來自於每個用戶的精雕細琢,它涵蓋了Java開發底層代碼中的方方面面,它既是大型項目開發中解決小問題的利器,也是小型項目中的效率擔當;

Hutool是項目中“util”包友好的替代,它節省了開發人員對項目中公用類和公用工具方法的封裝時間,使開發專注於業務,同時可以最大限度的避免封裝不完善帶來的bug。

這是官方對它的介紹,簡單點說,它通過一些封裝,將原來略顯複雜的API進一步優化,使得你在使用的時候能夠更加方便快捷,當然語法也會比原來更加簡單易懂。

包含組件

一個Java基礎工具類,對文件、流、加密解密、轉碼、正則、線程、XML等JDK方法進行封裝,組成各種Util工具類,同時提供以下組件:

模塊 介紹
hutool-aop JDK動態代理封裝,提供非IOC下的切面支持
hutool-bloomFilter 布隆過濾,提供一些Hash算法的布隆過濾
hutool-cache 簡單緩存實現
hutool-core 核心,包括Bean操作、日期、各種Util等
hutool-cron 定時任務模塊,提供類Crontab表達式的定時任務
hutool-crypto 加密解密模塊,提供對稱、非對稱和摘要算法封裝
hutool-db JDBC封裝後的數據操作,基於ActiveRecord思想
hutool-dfa 基於DFA模型的多關鍵字查找
hutool-extra 擴展模塊,對第三方封裝(模板引擎、郵件、Servlet、二維碼、Emoji、FTP、分詞等)
hutool-http 基於HttpUrlConnection的Http客戶端封裝
hutool-log 自動識別日誌實現的日誌門面
hutool-script 腳本執行封裝,例如Javascript
hutool-setting 功能更強大的Setting配置文件和Properties封裝
hutool-system 系統參數調用封裝(JVM信息等)
hutool-json JSON實現
hutool-captcha 圖片驗證碼實現
hutool-poi 針對POI中Excel的封裝
hutool-socket 基於Java的NIO和AIO的Socket封裝

可以根據需求對每個模塊單獨引入,也可以通過引入hutool-all方式引入所有模塊。

安裝

1、Maven項目

在項目的pom.xml的dependencies中加入以下內容:

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

2、非Maven項目

下載地址: https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.0.7/

在這裏插入圖片描述
下載hutool-all-X.X.X.jar即可。

下面對某幾個組件的使用進行一個入門。

類型轉換

1、常用類型轉換

在傳統的類型轉換過程中,我們需要使用到包裝類的valueof()方法,例如:

String s = "1234";
int num = Integer.valueOf(s);
double d = Double.valueOf(s);
float f = Float.valueOf(s);

但很顯然實際情況並沒有這麼簡單,在企業級的開發項目中,從前端傳遞過來的參數各式各樣,類型繁多,我們如何知曉參數類型並作對應的轉換呢?一般會先將所有參數轉成String類型,如Web中的HttpServletRequest的getParamer()方法得到的數據類型就永遠是String。轉成String之後再將參數轉成對應的數據類型,此時還需要考慮轉換異常的問題,所以通常還需要在轉換代碼外面使用try-catch。

爲了使轉換過程變得輕鬆愉快,HuTool爲我們提供了類型轉換工具——Convert。

來看看使用Convert該如何進行轉換:

String s = "1234";
int num = Convert.toInt(s);
double d = Convert.toDouble(s);
float f = Convert.toFloat(s);

首先在代碼風格上,Convert作了一個統一,統一使用Convert類作爲工具類進行類型轉換,而無需使用每個類型對應的包裝類。

當然了,Convert類的作用可遠不止如此,比如:

String[] s = { "1", "2", "3", "4", "5" };
Integer[] intArray = Convert.toIntArray(s);
Double[] doubleArray = Convert.toDoubleArray(s);
Float[] floatArray = Convert.toFloatArray(s);
Character[] charArray = Convert.toCharArray(s);

將數組轉換爲任意類型的數組。

對於集合,Convert同樣支持轉換:

Object[] objs= {"hello","world","java",1};
List<?> list = Convert.toList(objs);

還有日期類型:

String s = "2019-12-07";
Date date = Convert.toDate(s);

關於日期的處理,HuTool爲我們提供了專門的工具類,這個我們放到後面說。

2、其它類型轉換

通過Convert的convert()方法也能夠實現上述的所有操作,不信我們可以試一試:

String s = "1234";
int num = Convert.convert(Integer.class, s);
double d = Convert.convert(Double.class, s);
float f = Convert.convert(Float.class, s);

關於其它類型大家可以自己試一試,總之,通過convert()方法可以將任意類型轉換爲指定類型,但這種方法終歸是有侷限的,試問一下,我們如何將一個數組轉換成List類型呢?

我們可以通過一個重載方法convert( TypeReference reference, Object value ),該方法需要一個TypeReference對象參數,我們就可以創建TypeReference對象並通過嵌套泛型來指定需要轉換的類型,比如:

Object[] objs = { "hello", "world", "java"};
List<String> list = Convert.convert(new TypeReference<List<String>>() {}, objs);

Convert還提供了全角與半角符號之間的轉換,比如:

//將全角符轉爲半角符
String s = "1,2,3,4,5";
String dbc = Convert.toDBC(s);
//將半角符轉爲全角符
String sbc = Convert.toSBC(dbc);

可以看看運行結果,更加直觀:
在這裏插入圖片描述

3、編碼轉換

在一些場景下,比如表單提交,會將參數進行一個簡單的加密,此時通常會使用16進制轉換,當然了,我們在準備16進制轉換的時候也不會自己去寫,都是去百度找一個現成的。不過,有了HuTool就不需要了,它爲我們提供了方法用於完成16進制的轉換。

String s = "你好世界";
//轉換爲16進制字符串
String hex = Convert.toHex(s, CharsetUtil.CHARSET_UTF_8);
//轉換爲普通字符串
String str = Convert.hexToStr(hex, CharsetUtil.CHARSET_UTF_8);

運行結果:

e4bda0e5a5bde4b896e7958c
你好世界

注意編碼對象要相同,這裏都使用UTF-8編碼,所以順逆的轉換過程都是成功的,如果編碼不同,在轉爲普通字符串的時候就會出現亂碼。

還有Unicode編碼和字符串的轉換:

String s = "你好世界";
//轉換爲Unicode編碼
String unicode = Convert.strToUnicode(s);
//轉換爲普通字符串
String str = Convert.unicodeToStr(unicode);

運行結果:

\u4f60\u597d\u4e16\u754c
你好世界

Convert類還提供了convertCharset ()用於將字符串轉換爲指定編碼的字符串,比如在處理表單數據時通常要處理亂碼問題,如下:

String s = "你好世界";
//將字符串先轉成亂碼
String str = Convert.convertCharset(s, CharsetUtil.UTF_8, CharsetUtil.ISO_8859_1);
//處理亂碼
String result = Convert.convertCharset(str, CharsetUtil.ISO_8859_1, CharsetUtil.UTF_8);

運行結果:

????????????
你好世界

還有金額大小寫轉換的功能:

double money = 2019.127;
String s = Convert.digitToChinese(money);

運行結果:

貳仟零壹拾玖元壹角叄分

4、自定義類型轉換

Convert類的功能是不是非常強大呢?我們繼續來看,對於數據類型轉換,肯定是做不到包含所有數據類型的,因爲Java面向對象的特性,但是HuTool提供了自定義類型轉換。

ConverterRegistry converterRegistry = ConverterRegistry.getInstance();
converterRegistry.putCustom(Person.class, CustomConverter.class);
String[] str = { "20", "張三" };
Person person = converterRegistry.convert(Person.class, str);
System.out.println(person);

運行結果:

Person [age=20, name=張三]

該轉換器將一個數組類型轉換爲了Person對象,它是如何實現的呢?(分三步)

  1. 自定義類實現Converter接口,並重寫convert()方法
  2. 註冊自定義的轉換器
  3. 實現轉換

先定義一個Person類:

public class Person {

	private int age;
	private String name;

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "Person [age=" + age + ", name=" + name + "]";
	}
}

然後自定義類實現Converter接口,並重寫方法:

public class CustomConverter implements Converter<Person> {

	@Override
	public Person convert(Object value, Person person) throws IllegalArgumentException {
		person = new Person();
		String[] str = Convert.toStrArray(value);
		person.setAge(Convert.toInt(str[0]));
		person.setName(str[1]);
		return person;
	}
}

該方法將傳遞過來的數據封裝成Person對象並返回,實現類型轉換。

接着註冊自定義的轉換器:

ConverterRegistry converterRegistry = ConverterRegistry.getInstance();
converterRegistry.putCustom(Person.class, CustomConverter.class);

現在就可以使用我們的轉換器了,也就是剛剛的代碼:

String[] str = { "20", "張三" };
Person person = converterRegistry.convert(Person.class, str);
System.out.println(person);

需要轉換的數據是什麼樣式的,完全由你自定義的轉換器決定,非常靈活,可根據自己的需求隨意定製。

日期時間處理

對於日期時間的處理,Java提供了Date類和Calendar類,但就是因爲有了更多的選擇,使得日期時間轉換的操作變得混亂和複雜,爲此,HuTool提供了DateUtil工具。

1、Date、long、Calendar的相互轉換

使用DateUtil可以實現Date、long和Calendar之間的相互轉換,如下:

// Calendar轉爲Date
Date date = DateUtil.date(Calendar.getInstance());
// long轉爲Date
Date date2 = DateUtil.date(System.currentTimeMillis());
// Date轉爲Calendar
Calendar calendar = DateUtil.calendar(date);
// long轉爲Calendar
Calendar calendar2 = DateUtil.calendar(System.currentTimeMillis());

2、日期字符串轉換爲Date

String s = "2019-12-07";
DateTime dateTime = DateUtil.parse(s);
System.out.println(dateTime);

運行結果:

2019-12-07 00:00:00

該方法能夠將日期字符串轉換爲Date類型,它能夠自動識別以下格式的字符串:

  1. yyyy-MM-dd HH:mm:ss
  2. yyyy-MM-dd
  3. HH:mm:ss
  4. yyyy-MM-dd HH:mm
  5. yyyy-MM-dd HH:mm:ss.SSS

3、格式化日期

格式化日期很簡單,和Java的API沒什麼區別。

String s = "2019-12-07";
DateTime date = DateUtil.parse(s);

String dateStr = DateUtil.format(date, "yyyy/MM/dd");
System.out.println(dateStr);
String dateStr2 = DateUtil.formatDate(date);
System.out.println(dateStr2);
String dateStr3 = DateUtil.formatDateTime(date);
System.out.println(dateStr3);
String dateStr4 = DateUtil.formatTime(date);
System.out.println(dateStr4);

通過format()方法可以將日期字符串轉換爲指定的格式,不過,DateUtil提供了其它的一些方法來作爲常用的日期格式轉換,看運行結果即可:

2019/12/07
2019-12-07
2019-12-07 00:00:00
00:00:00

4、獲取年、月、日

對於年、月、日的獲取,DateUtil也提供了非常簡便的獲取方式:

// 獲取當前日期時間
DateTime date = DateUtil.date();
System.out.println(date);
// 獲取年
int year = DateUtil.year(date);
System.out.println(year);
// 獲取月	從0開始
int month = DateUtil.month(date);	
System.out.println(month);

運行結果:

2019-12-07 21:45:42
2019
11

5、日期時間偏移量

對於日期時間的偏移,DateUtil同樣能夠很方便地實現,如下:

String s = "2019-12-06 21:46:00";
DateTime date = DateUtil.parse(s);

// 日期往後偏移一天
DateTime dateTime = DateUtil.offset(date, DateField.DAY_OF_MONTH, 1);
System.out.println(dateTime);

// 日期往後偏移兩天
DateTime dateTime2 = DateUtil.offsetDay(dateTime, 2);
System.out.println(dateTime2);

// 日期往後偏移一個小時
DateTime dateTime3 = DateUtil.offsetHour(date, 1);
System.out.println(dateTime3);

運行結果:

2019-12-07 21:46:00
2019-12-09 21:46:00
2019-12-06 22:46:00

關於日期時間的偏移,通過offset()方法即可實現,該方法的第二個參數可傳入偏移的單位,不過DateUtil還提供了一些比較常用的偏移方法,比如偏移天數、偏移小時。

對於與當前十分接近的日期時間,DateUtil也提供了一些較爲常用的方法,比如昨天、明天、上週、下週、上個月、下個月等:

DateTime yesrerday = DateUtil.yesterday();
System.out.println(yesrerday);
		
DateTime tomorrow = DateUtil.tomorrow();
System.out.println(tomorrow);
		
DateTime lastMonth = DateUtil.lastMonth();
System.out.println(lastMonth);
		
DateTime nextMonth = DateUtil.nextMonth();
System.out.println(nextMonth);
		
DateTime lastWeek = DateUtil.lastWeek();
System.out.println(lastWeek);
		
DateTime nextWeek = DateUtil.nextWeek();
System.out.println(nextWeek);

運行結果:

2019-12-06 22:02:29
2019-12-08 22:02:29
2019-11-07 22:02:29
2020-01-07 22:02:29
2019-11-30 22:02:29
2019-12-14 22:02:29

6、計算日期時間差

String s1 = "2019-12-06 22:15:00";
DateTime date1 = DateUtil.parse(s1);
String s2 = "2019-12-08 22:15:00";
DateTime date2 = DateUtil.parse(s2);
// 計算相差的天數
long day = DateUtil.between(date1, date2, DateUnit.DAY);
System.out.println(day);
// 計算相差的小時數
long hour = DateUtil.between(date1, date2, DateUnit.HOUR);
System.out.println(hour);

運行結果:

2
48

對於兩個日期時間的差值,通過between()方法能夠很輕鬆地得到,該方法的第三個參數是需要計算的差值的單位。

7、計時器

DateUtil類還封裝了計時器功能,用過傳統的Timer計時器的同學就會知道,Timer計時器略顯複雜,而DateUtil的封裝則恰到好處。

TimeInterval timer = DateUtil.timer();
// 延遲2秒
Thread.sleep(2000);
// 花費的時間,單位:毫秒
long interval = timer.interval();
System.out.println(interval);
// 花費的時間,單位:分
long intervalMinute = timer.intervalMinute();
System.out.println(intervalMinute);

運行結果:

2000
0

還有很多其它的方法,篇幅有限,就不一一例舉了。

8、其它

考慮到一些比較常見的場景,例如計算一個人的年齡,判斷給定年份是否爲閏年,DateUtil也給出了相應的解決辦法。

int age = DateUtil.ageOfNow("1999-08-08");
System.out.println(age);
boolean leapYear = DateUtil.isLeapYear(2019);
System.out.println(leapYear);

運行結果:

20
false

IO操作

IO操作是Java中比較重要的操作之一,爲此,Java提供了InputStream、OutputStream、Reader、Writer等接口,而實現類又非常的多,往往選擇一多,我們就不知道該如何選擇,而HuTool爲我們封裝了一系列的工具類。

FileUtil(文件操作工具類)

既然是IO流,那就離不開文件操作,HuTool爲我們提供了FileUtil工具類用來解決大部分的文件操作問題。

對於文件操作的方法,有Linux基礎的同學肯定非常熟悉,開源項目的作者努力將方法名與Linux保持一致,比如創建文件的方法不是createFile()而是touch()。

File[] files = FileUtil.ls("E:");
for (File file : files) {
	System.out.println(file);
}

運行結果:

E:\$RECYCLE.BIN
E:\androidSdk
E:\androidstudio
E:\b2631f36a0808f7d3cab19543d645e63
E:\flutter
E:\Java
E:\MailMasterData
E:\QLDownload
E:\QQPCmg
E:\QQPCmgr
E:\qycache
E:\System Volume Information
E:\test.txt
E:\Tool
E:\迅雷下載

ls()方法會列出給定路徑下的所有目錄和文件。

FileUtil.touch("E:/test/hello.txt");

touch()方法用於創建文件,如果父目錄不存在也自動創建,比如這裏的hello.txt文件,倘若E盤下沒有test目錄,則會先創建test文件夾,再在test目錄下創建hello.txt文件。

其它方法也如上所示使用,就不一一演示了:

  • mkdir 創建目錄,會遞歸創建每層目錄
  • del 刪除文件或目錄(遞歸刪除,不判斷是否爲空),這個方法相當於Linux的delete命令
  • copy 拷貝文件或目錄

注意:對於del()方法,它會直接刪除目錄而不判斷其是否爲空,所以請謹慎使用。

IOUtil(IO工具類)

第二個便是IOUtil,該工具類主要針對輸入輸出流的一個封裝。

1、文件複製

針對文件複製操作,IOUtil能夠很輕鬆地完成。

BufferedInputStream inputStream = FileUtil.getInputStream("C:/Users/Administrator/Desktop/eclipseworkspace/HuToolDemo/src/com/wwj/test/TestDemo.java");
BufferedOutputStream outputStream = FileUtil.getOutputStream("E:/test.txt");
long copySize = IoUtil.copy(inputStream, outputStream, IoUtil.DEFAULT_BUFFER_SIZE);

這裏就複製了一下當前的java文件並將其保存至E盤下的test.txt文件中。

2、讀流寫流

讀流寫流也是IO操作中使用頻率非常高的操作,它跟傳統的方式沒有太大區別,只不過對調用者進行了統一。

BufferedInputStream inputStream = FileUtil.getInputStream("C:\\Users\\Administrator\\Desktop\\eclipseworkspace\\HuToolDemo\\src\\com\\wwj\\test\\TestDemo.Java");
BufferedOutputStream outputStream = FileUtil.getOutputStream("E:\\test.txt");
int len = -1;
byte[] buffer = new byte[1024];
while ((len = inputStream.read(buffer)) != -1) {
	outputStream.write(buffer, 0, len);
}
IoUtil.close(inputStream);
IoUtil.close(outputStream);

下面列出關於讀寫流操作相關的方法:

  • readBytes 返回byte數組(讀取圖片等)
  • readHex 讀取16進制字符串
  • readObj 讀取序列化對象(反序列化)
  • readLines 按行讀取

對於寫流操作,IoUtil提供了兩個write()的重載方法,當然也可以直接使用輸出流的write()方法,而事實上,IoUtil的write()方法也是這麼做的。

我們再來看看IoUtil如何讀寫圖片,對於圖片的讀寫操作,它提供了readBytes()方法,使用該方法讀寫圖片簡直不要太簡單:

BufferedInputStream inputStream = FileUtil.getInputStream("C:\\Users\\Administrator\\Desktop\\eclipseworkspace\\HuToolDemo\\默認圖表.png");
BufferedOutputStream outputStream = FileUtil.getOutputStream("E:\\test.png");
byte[] bytes = IoUtil.readBytes(inputStream);
outputStream.write(bytes);
IoUtil.close(inputStream);
IoUtil.close(outputStream);

這樣即可完成圖片的讀寫。

IoUtil還提供了一些其它方法用於簡化編程,比如:toStream()方法用於將某些對象轉換爲流對象;writeObjects()方法用於將可序列化對象序列化後寫入到流中。

3、釋放流資源

IO操作中的一個好習慣就是用完哪個流就關掉哪個流,而關閉操作會面臨兩個問題:

  • 被關閉的對象爲空
  • 對象關閉失敗

而IoUtil提供的close()方法則很好地解決了這些問題,我們只需將要關閉的流傳入close()方法即可。

FileTypeUtil(文件類型判斷工具類)

FileTypeUtil是一個判斷文件類型的工具類,它並不是通過文件的擴展名來確定文件類型,而是通過讀取文件的首部幾個二進制位來判斷。

File file = FileUtil.file("C:\\Users\\Administrator\\Desktop\\eclipseworkspace\\HuToolDemo\\默認圖表.png");
String type = FileTypeUtil.getType(file);
Console.log(type);

運行結果:

png

FileReader(文件讀取)

雖然FileUtil已經提供了關於文件讀寫的API,但是根據職責分離原則,HuTool還是爲我們提供了FileReader類專門讀取文件。

在JDK中同樣提供了FileReader類,但並不好用,HuTool正是對它進行的一個升級。

FileReader fileReader = new FileReader("test.properties");
String result = fileReader.readString();
System.out.println(result);

運行結果:

username=root
password=123456

該類還提供了一些常用的方法幫助文件讀取:

  • readBytes
  • readString
  • readLines

文件寫入(FileWriter)

有文件讀取,肯定就會有文件寫入,使用方法和FileReader是一樣的,這裏就不做代碼演示了。

寫入方式分爲追加和覆蓋兩種模式,追加的話可以用append()方法,覆蓋可以用write()方法;當然你也可以直接使用write()方法,並將寫入模式作爲第二個參數傳入。

資源訪問

在Java開發中,資源訪問是比較常見的操作,例如在操作數據庫、整合框架的時候,需要頻繁地訪問配置文件,通常我們會將配置文件放在類路徑下,方便訪問:

InputStream in = TestDemo.class.getResource("test.properties").openStream();

對於資源訪問這種頻繁而且麻煩的操作,HuTool對其進行了封裝。

ClassPathResource resource = new ClassPathResource("test.properties");
Properties properties = new Properties();
properties.load(resource.getStream());
Console.log(properties);

運行結果:

{password=123456, username=root}

當然,對於資源訪問的封裝遠不止如此,這個放到後面說。

最後

以上內容只是HuTool項目的冰山一角,我將在下篇相關文章中繼續介紹該項目下封裝的一些工具類。

發佈了115 篇原創文章 · 獲贊 9041 · 訪問量 69萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章