7. JDK拍了拍你:字串拼接一定記得用MessageFormat#format
阿新 • • 發佈:2020-12-29
[TOC]
![](https://img-blog.csdnimg.cn/20201226172156506.png#pic_center)
> 分享、成長,拒絕淺藏輒止。關注公號【**BAT的烏托邦**】,回覆`專欄`獲取原創專欄:重學Spring、重學MyBatis、中介軟體、雲端計算...本文已被 [https://www.yourbatman.cn](https://www.yourbatman.cn) 收錄。
# ✍前言
你好,我是A哥(YourBatman)。本文所屬專欄:**Spring型別轉換**,公號後臺回覆專欄名即可獲取全部內容。
在日常開發中,我們經常會有**格式化**的需求,如日期格式化、數字格式化、錢幣格式化等等。
![](https://img-blog.csdnimg.cn/20201221061443288.png#pic_center)
格式化器的作用似乎跟轉換器的作用類似,但是它們的關注點卻不一樣:
- 轉換器:將型別S轉換為型別T,關注的是型別而非格式
- 格式化器: String `<->` Java型別。這麼一看它似乎和`PropertyEditor`類似,但是它的關注點是字串的**格式**
Spring有自己的格式化器抽象`org.springframework.format.Formatter`,但是談到格式化器,必然就會聯想起來JDK自己的`java.text.Format`體系。為後文做好鋪墊,本文就先介紹下JDK為我們提供了哪些格式化能力。
## 版本約定
- JDK:8
![](https://img-blog.csdnimg.cn/2020122617255122.png#pic_center)
# ✍正文
Java裡從來都缺少不了字串拼接的活,JDK也提供了多種“工具”供我們使用,如:StringBuffer、StringBuilder以及最直接的`+`號,相信這些大家都有用過。但這都不是本文的內容,本文將講解格式化器,給你提供一個新的思路來拼接字串,並且是推薦方案。
JDK內建有格式化器,便是`java.text.Format`體系。它是個抽象類,提供了兩個抽象方法:
```java
public abstract class Format implements Serializable, Cloneable {
public abstract StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos);
public abstract Object parseObject (String source, ParsePosition pos);
}
```
- **format**:將Object格式化為String,並將此String放到toAppendTo裡面
- **parseObject**:講String轉換為Object,是format方法的逆向操作
Java SE針對於Format抽象類對於常見的應用場景分別提供了三個子類實現:
![](https://img-blog.csdnimg.cn/20201225063338484.png#pic_center)
## DateFormat:日期時間格式化
抽象類。用於用於格式化日期/時間型別`java.util.Date`。雖然是抽象類,但它提供了幾個靜態方法用於獲取它的例項:
```java
// 格式化日期 + 時間
public final static DateFormat getInstance() {
return getDateTimeInstance(SHORT, SHORT);
}
public final static DateFormat getDateTimeInstance(int dateStyle, int timeStyle, Locale aLocale){
return get(timeStyle, dateStyle, 3, aLocale);
}
// 格式化日期
public final static DateFormat getDateInstance(int style, Locale aLocale) {
return get(0, style, 2, aLocale);
}
// 格式化時間
public final static DateFormat getTimeInstance(int style, Locale aLocale){
return get(style, 0, 1, aLocale);
}
```
![](https://img-blog.csdnimg.cn/20201225063820907.png#pic_center)
有了這些靜態方法,你可在**不必關心**具體實現的情況下直接使用:
```java
/**
* {@link DateFormat}
*/
@Test
public void test1() {
Date curr = new Date();
// 格式化日期 + 時間
System.out.println(DateFormat.getInstance().getClass() + "-->" + DateFormat.getInstance().format(curr));
System.out.println(DateFormat.getDateTimeInstance().getClass() + "-->" + DateFormat.getDateTimeInstance().format(curr));
// 格式化日期
System.out.println(DateFormat.getDateInstance().getClass() + "-->" + DateFormat.getDateInstance().format(curr));
// 格式化時間
System.out.println(DateFormat.getTimeInstance().getClass() + "-->" + DateFormat.getTimeInstance().format(curr));
}
```
執行程式,輸出:
```java
class java.text.SimpleDateFormat-->20-12-25 上午7:19
class java.text.SimpleDateFormat-->2020-12-25 7:19:30
class java.text.SimpleDateFormat-->2020-12-25
class java.text.SimpleDateFormat-->7:19:30
```
嗯,可以看到底層實現其實是咱們熟悉的`SimpleDateFormat`。實話說,這種做法不常用,狠一點:基本不會用(框架開發者可能會用做兜底實現)。
### SimpleDateFormat
一般來說,我們會直接使用`SimpleDateFormat`來對Date進行格式化,它可以自己指定Pattern,個性化十足。如:
```java
@Test
public void test2() {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); // yyyy-MM-dd HH:mm:ss
System.out.println(dateFormat.format(new Date()));
}
```
執行程式,輸出:
```java
2020-12-25
```
關於`SimpleDateFormat`的使用方式不再囉嗦,不會的就可走自行勸退手續了。此處只提醒一點:**SimpleDateFormat執行緒不安全**。
> 說明:JDK 8以後不再建議使用Date型別,也就不會再使用到DateFormat。同時我個人建議:在專案中可**強制**嚴令禁用
## NumberFormat:數字格式化
抽象類。用於格式化數字,它可以對數字進行任意格式化,如小數、百分數、十進位制數等等。它有兩個實現類:
![](https://img-blog.csdnimg.cn/20201226104107361.png#pic_center)
類結構和DateFormat類似,也提供了`getXXXInstance`靜態方法給你直接使用,無需關心底層實現:
![](https://img-blog.csdnimg.cn/20201225072829183.png#pic_center)
```java
@Test
public void test41() {
double myNum = 1220.0455;
System.out.println(NumberFormat.getInstance().getClass() + "-->" + NumberFormat.getInstance().format(myNum));
System.out.println(NumberFormat.getCurrencyInstance().getClass() + "-->" + NumberFormat.getCurrencyInstance().format(myNum));
System.out.println(NumberFormat.getIntegerInstance().getClass() + "-->" + NumberFormat.getIntegerInstance().format(myNum));
System.out.println(NumberFormat.getNumberInstance().getClass() + "-->" + NumberFormat.getNumberInstance().format(myNum));
System.out.println(NumberFormat.getPercentInstance().getClass() + "-->" + NumberFormat.getPercentInstance().format(myNum));
}
```
執行程式,輸出:
```java
class java.text.DecimalFormat-->1,220.045
class java.text.DecimalFormat-->¥1,220.05
class java.text.DecimalFormat-->1,220
class java.text.DecimalFormat-->1,220.045
class java.text.DecimalFormat-->122,005%
```
這一看就知道DecimalFormat是NumberFormat的主力了。
### DecimalFormat
Decimal:小數,小數的,十進位的。
用於格式化**十進位制數字**。它具有各種特性,可以解析和格式化數字,包括:西方數字、**阿拉伯數字**和印度數字。它還支援不同種類的數字,包括:整數(123)、小數(123.4)、科學記數法(1.23E4)、百分數(12%)和**貨幣**金額($123)。所有這些都可以進行本地化。
下面是它的構造器:
![](https://img-blog.csdnimg.cn/20201226104953453.png#pic_center)
其中最為重要的就是這個pattern(不帶引數的構造器一般不會用),它表示格式化的模式/模版。一般來說我們對DateFormat的pattern比較熟悉,但對數字格式化的模版符號瞭解甚少。這裡我就幫你整理出這個表格(資訊源自JDK官網),記得蒐藏哦:
符號 | Localtion | 是否本地化 | 釋義
-------- | ----- | ----- | -----
`0` | Number | 是 | Digit
`#` | Number | 是 | Digit。若是0就顯示為空
`.` | Number | 是 | 小數/貨幣分隔符
`-` | Number | 是 | 就代表減號
`,` | Number | 是 | 分組分隔符
`E` | Number | 是 | 科學計數法分隔符(位數和指數)
`%` | 前/字尾 | 是 | 乘以100並顯示為百分數
`¤` | 前/字尾 | 否 | 貨幣記號。若連續出現兩次就用國際貨幣符號代替
`'` | 前後綴 | 否 | 用於引用特殊字元。作用類似於轉義字元
> 說明:Number和Digit的區別:
> - Number是個抽象概念,其表達形式可以是數字、手勢、聲音等等。如1024就是個number
> - Digit是用來表達的**單獨符號**。如0-9這是個digit就可以用來表示number,如1024就是由1、0、2、4這四個digit組成的
看了這個表格的符號規則,估計很多同學還是一臉懵逼。不囉嗦了,上乾貨
#### 一、0和#的使用(最常見使用場景)
這是**最經典、最常見**的使用場景,甚至來說你有可能職業生涯**只**會用到此場景。
```java
/**
* {@link DecimalFormat}
*/
@Test
public void test4() {
double myNum = 1220.0455;
System.out.println("===============0的使用===============");
System.out.println("只保留整數部分:" + new DecimalFormat("0").format(myNum));
System.out.println("保留3位小數:" + new DecimalFormat("0.000").format(myNum));
System.out.println("整數部分、小數部分都5位。不夠的都用0補位(整數高位部,小數低位補):" + new DecimalFormat("00000.00000").format(myNum));
System.out.println("===============#的使用===============");
System.out.println("只保留整數部分:" + new DecimalFormat("#").format(myNum));
System.out.println("保留2為小數並以百分比輸出:" + new DecimalFormat("#.##%").format(myNum));
// 非標準數字(不建議這麼用)
System.out.println("===============非標準數字的使用===============");
System.out.println(new DecimalFormat("666").format(myNum));
System.out.println(new DecimalFormat(".6666").format(myNum));
}
```
執行程式,輸出:
```java
===============0的使用===============
只保留整數部分:1220
保留3位小數:1220.045
整數部分、小數部分都5位。不夠的都用0補位(整數高位部,小數低位補):01220.04550
===============#的使用===============
只保留整數部分:1220
保留2為小數並以百分比輸出:122004.55%
===============非標準數字的使用===============
661220
1220.666
```
通過此案例,大致可得出如下結論:
- 整數部分:
- 0和#都可用於取出全部整數部分
- 0的個數決定整數部分長度,不夠高位補0;#則無此約束,N多個#是一樣的效果
- 小數部分:
- 可保留小數點後N位(0和#效果一樣)
- 若小數點後位數不夠,若使用的0那就低位補0,若使用#就不補(該是幾位就是幾位)
- 數字(1-9):並不建議模版裡直接寫1-9這樣的數字,瞭解下即可
#### 二、科學計數法E
如果你不是在證券/銀行行業,這個大概率是用不著的(即使在,你估計也不會用它)。來幾個例子感受一把就成:
```java
@Test
public void test5() {
double myNum = 1220.0455;
System.out.println(new DecimalFormat("0E0").format(myNum));
System.out.println(new DecimalFormat("0E00").format(myNum));
System.out.println(new DecimalFormat("00000E00000").format(myNum));
System.out.println(new DecimalFormat("#E0").format(myNum));
System.out.println(new DecimalFormat("#E00").format(myNum));
System.out.println(new DecimalFormat("#####E00000").format(myNum));
}
```
執行程式,輸出:
```java
1E3
1E03
12200E-00001
.1E4
.1E04
1220E00000
```
#### 三、分組分隔符,
分組分隔符比較常用,它就是我們常看到的逗號`,`
```java
@Test
public void test6() {
double myNum = 1220.0455;
System.out.println(new DecimalFormat(",###").format(myNum));
System.out.println(new DecimalFormat(",##").format(myNum));
System.out.println(new DecimalFormat(",##").format(123456789));
// 分隔符,左邊是無效的
System.out.println(new DecimalFormat("###,##").format(myNum));
}
```
執行程式,輸出:
```java
1,220
12,20
1,23,45,67,89
12,20
```
#### 四、百分號%
在展示層面也比較常用,用於把一個數字用%形式表示出來。
```java
@Test
public void test42() {
double myNum = 1220.0455;
System.out.println("百分位表示:" + new DecimalFormat("#.##%").format(myNum));
System.out.println("千分位表示:" + new DecimalFormat("#.##\u2030").format(myNum));
}
```
執行程式,輸出:
```java
百分位表示:122004.55%
千分位表示:1220045.5‰
```
#### 五、本地貨幣符號¤
嗯,這個符號`¤`,鍵盤竟無法直接輸出,得使用軟鍵盤(建議使用copy大法)。
```java
@Test
public void test7() {
double myNum = 1220.0455;
System.out.println(new DecimalFormat(",000.00¤").format(myNum));
System.out.println(new DecimalFormat(",000.¤00").format(myNum));
System.out.println(new DecimalFormat("¤,000.00").format(myNum));
System.out.println(new DecimalFormat("¤,000.¤00").format(myNum));
// 世界貨幣表達形式
System.out.println(new DecimalFormat(",000.00¤¤").format(myNum));
}
```
執行程式,輸出:
```java
1,220.05¥
1,220.05¥
¥1,220.05
1,220.05¥¥
¥1,220.05¥
1,220.05CNY
```
注意最後一條結果:如果連續出現兩次,代表貨幣符號的國際代號。
> 說明:結果預設都做了Locale本地化處理的,若你在其它國家就不會再是¥人名幣符號嘍
DecimalFormat就先介紹到這了,其實掌握了它就基本等於掌握了NumberFormat。接下來再簡要看看它另外一個“兒子”:ChoiceFormat。
### ChoiceFormat
Choice:精選的,仔細推敲的。
這個格式化器非常有意思:**相當於以數字為鍵,字串為值的鍵值對**。使用一組double型別的陣列作為鍵,一組String型別的陣列作為值,兩陣列相同(不一定必須是相同,見示例)索引值的元素作為一對。
```java
@Test
public void test8() {
double[] limits = {1, 2, 3, 4, 5, 6, 7};
String[] formats = {"週一", "週二", "週三", "週四", "週五", "週六", "周天"};
NumberFormat numberFormat = new ChoiceFormat(limits, formats);
System.out.println(numberFormat.format(1));
System.out.println(numberFormat.format(4.3));
System.out.println(numberFormat.format(5.8));
System.out.println(numberFormat.format(9.1));
System.out.println(numberFormat.format(11));
}
```
執行程式,輸出:
```java
週一
週四
週五
周天
周天
```
結果解釋:
1. 4.3位於4和5之間,取值4;5.8位於5和6之間,取值5
2. 9.1和11均超過了陣列最大值(或者說找不到匹配的),則取值**最後一對鍵值對**。
可能你會想這有什麼使用場景???是的,不得不承認它的使用場景較少,本文下面會介紹下它和`MessageFormat`的一個使用場景。
如果說`DateFormat`和`NumberFormat`都用沒什麼花樣,主要記住它的pattern語法格式就成,那麼就下來這個格式化器就是本文的主菜了,使用場景非常的廣泛,它就是`MessageFormat`。
## MessageFormat:字串格式化
MessageFormat提供了一種**與語言無關**(不管你在中國還是其它國家,效果一樣)的方式生成**拼接訊息/拼接字串**的方法。使用它來構造顯示給終端使用者的訊息。MessageFormat接受一組物件,對它們進行格式化,然後在模式的適當位置**插入**格式化的字串。
先來個最簡單的使用示例體驗一把:
```java
/**
* {@link MessageFormat}
*/
@Test
public void test9() {
String sourceStrPattern = "Hello {0},my name is {1}";
Object[] args = new Object[]{"girl", "YourBatman"};
String formatedStr = MessageFormat.format(sourceStrPattern, args);
System.out.println(formatedStr);
}
```
執行程式,輸出:
```java
Hello girl,my name is YourBatman
```
有沒有中似曾相似的感覺,是不是和`String.format()`的作用特別像?是的,它倆的用法區別,到底使用稅文下也會討論。
要熟悉MessageFormat的使用,主要是要熟悉它的引數模式(你也可以理解為pattern)。
### 引數模式
MessageFormat採用`{}`來標記需要被**替換/插入**的部分,其中`{}`裡面的引數結構具有一定模式:
```java
ArgumentIndex[,FormatType[,FormatStyle]]
```
- `ArgumentIndex`:**非必須**。從`0`開始的索引值
- `FormatType`:**非必須**。使用不同的`java.text.Format`實現類對入參進行格式化處理。它能有如下值:
- number:呼叫NumberFormat進行格式化
- date:呼叫DateFormat進行格式化
- time:呼叫DateFormat進行格式化
- **choice**:呼叫ChoiceFormat進行格式化
- `FormatStyle`:**非必須**。設定FormatType使用的樣式。它能有如下值:
- short、medium、long、full、integer、currency、percent、**SubformPattern(如日期格式、數字格式#.##等)**
> 說明:FormatType和FormatStyle只有在傳入值為日期時間、數字、百分比等型別時才有可能需要設定,使用得並不多。畢竟:我在外部格式化好後再放進去不香嗎?
```java
@Test
public void test10() {
MessageFormat messageFormat = new MessageFormat("Hello, my name is {0}. I’am {1,number,#.##} years old. Today is {2,date,yyyy-MM-dd HH:mm:ss}");
// 亦可通過程式設計式 顯示指定某個位置要使用的格式化器
// messageFormat.setFormatByArgumentIndex(1, new DecimalFormat("#.###"));
System.out.println(messageFormat.format(new Object[]{"YourBatman", 24.123456, new Date()}));
}
```
執行程式,輸出:
```java
Hello, my name is YourBatman. I’am 24.12 years old. Today is 2020-12-26 15:24:28
```
它既可以直接在模版裡指定格式化模式型別,也可以通過API方法set指定格式化器,當然你也可以再外部格式化好後再放進去,三種方式均可,任君選擇。
### 注意事項
下面基於此示例,對MessageFormat的使用注意事項作出幾點強調。
```java
@Test
public void test11() {
System.out.println(MessageFormat.format("{1} - {1}", new Object[]{1})); // {1} - {1}
System.out.println(MessageFormat.format("{0} - {1}", new Object[]{1})); // 輸出:1 - {1}
System.out.println(MessageFormat.format("{0} - {1}", new Object[]{1, 2, 3})); // 輸出:1 - 2
System.out.println("---------------------------------");
System.out.println(MessageFormat.format("'{0} - {1}", new Object[]{1, 2})); // 輸出:{0} - {1}
System.out.println(MessageFormat.format("''{0} - {1}", new Object[]{1, 2})); // 輸出:'1 - 2
System.out.println(MessageFormat.format("'{0}' - {1}", new Object[]{1, 2})); // {0} - 2
// 若你資料庫值兩邊都需要''包起來,請你這麼寫
System.out.println(MessageFormat.format("''{0}'' - {1}", new Object[]{1, 2})); // '1' - 2
System.out.println("---------------------------------");
System.out.println(MessageFormat.format("0} - {1}", new Object[]{1, 2})); // 0} - 2
System.out.println(MessageFormat.format("{0 - {1}", new Object[]{1, 2})); // java.lang.IllegalArgumentException: Unmatched braces in the pattern.
}
```
1. 引數模式的索引值**必須**從0開始,否則所有索引值無效
2. 實際傳入的引數個數可以和索引個數不匹配,不報錯(能匹配上幾個算幾個)
3. 兩個單引號`''`才算作一個`'`,若只寫一個將被忽略甚至影響整個表示式
1. 謹慎使用單引號`'`
2. 關注`'`的匹配關係
5. `{}`只寫左邊報錯,只寫右邊正常輸出(注意引數的對應關係)
### static方法的效能問題
我們知道`MessageFormat`提供有一個static靜態方法,非常方便的的使用:
```java
public static String format(String pattern, Object ... arguments) {
MessageFormat temp = new MessageFormat(pattern);
return temp.format(arguments);
}
```
可以清晰看到,該靜態方法**本質上**還是構造了一個`MessageFormat`例項去做格式化的。因此:若你要多次(如高併發場景)格式化**同一個模版**(引數可不一樣)的話,那麼提前建立好一個**全域性的**(非static) MessageFormat例項再執行格式化是最好的,而非一直呼叫其靜態方法。
> 說明:若你的系統非高併發場景,此效能損耗基本無需考慮哈,怎麼方便怎麼來。畢竟**朝生夕死**的物件對JVM來說沒啥壓力
### 和String.format選誰?
二者都能用於字串拼接(格式化)上,撇開MessageFormat支援各種模式不說,我們只需要考慮它倆的效能上差異。
- **MeesageFormat**:先分析(模版可提前分析,且可以只分析一次),再在指定位置上插入相應的值
- 分析:遍歷字串,維護一個`{}`陣列並記錄位置
- 填值
- **String.format**:該靜態方法是採用執行時用**正則表示式** 匹配到佔位符,然後執行替換的
- 正則表示式為`"%(\\d+\\$)?([-#+ 0,(\\<]*)?(\\d+)?(\\.\\d+)?([tT])?([a-zA-Z%])"`
- 根據正則匹配到佔位符列表和位置,然後填值
一說到正則表示式,我心裡就發觸,因為它對效能是**不友好**的,所以孰優孰劣,高下立判。
> 說明:還是那句話,沒有絕對的誰好誰壞,如果你的系統對效能不敏感,那就是方便第一
### 經典使用場景
這個就很多啦,最常見的有:HTML拼接、SQL拼接、異常資訊拼接等等。
比如下面這個SQL拼接:
```java
StringBuilder sb =new StringBuilder();
sb.append("insert into user (");
sb.append(" name,");
sb.append(" accountId,");
sb.append(" zhName,");
sb.append(" enname,");
sb.append(" status");
sb.append(") values (");
sb.append(" ''{0}'',");
sb.append(" {1},");
sb.append(" ''{2}'',");
sb.append(" ''{3}'',");
sb.append(" {4},");
sb.append(")");
Object[] args = {name, accountId, zhName, enname, status};
// 最終SQL
String sql = MessageFormat.format(sb.toString(), arr);
```
你看,多工整。
> 說明:如果值是字串需要`'`包起來,那麼請使用兩邊各兩個包起來
# ✍總結
本文內容介紹了JDK原生的格式化器知識點,主要作用在這三個方面:
- **DateFormat**:日期時間格式化
- **NumberFormat**:數字格式化
- **MessageFormat**:字串格式化
Spring是直接面向使用者的框架產品,很顯然這些是不夠用的,並且JDK的格式化器在設計上存在一些弊端。比如經常被吐槽的:日期/時間型別格式化器`SimpleDateFormat`為毛在java.text包裡,而它格式化的型別Date卻在java.util包內,這實為不合適。
有了JDK格式化器作為基礎,下篇我們就可以浩浩蕩蕩的走進Spring格式化器的大門了,看看它是如何優於JDK進行設計和抽象的。
---
### ✔✔✔推薦閱讀✔✔✔
【Spring型別轉換】系列:
- [1. 揭祕Spring型別轉換 - 框架設計的基石](https://mp.weixin.qq.com/s/5daOOdhIFqrGbpgtnuQMNw)
- [2. Spring早期型別轉換,基於PropertyEditor實現](https://mp.weixin.qq.com/s/Afu8YYyREoynAXS6YrJe7g)
- [3. 搞定收工,PropertyEditor就到這](https://mp.weixin.qq.com/s/--UO3pH1nxTW3f5nQvEnkg)
- [4. 上新了Spring,全新一代型別轉換機制](https://mp.weixin.qq.com/s/SMKs3fYoJm1Dfpy-6m_9ZQ)
- [5. 穿過擁擠的人潮,Spring已為你製作好高階賽道](https://mp.weixin.qq.com/s/wnuqbgnS-D-U48XrxHKIvg)
- [6. 抹平差異,統一型別轉換服務ConversionService](https://mp.weixin.qq.com/s/9MPkCSM9AbsgKAFQ1eXBNQ)
【Jackson】系列:
- [1. 初識Jackson -- 世界上最好的JSON庫](https://mp.weixin.qq.com/s/iqSN4HUoIdX0kGcSdnD7EA)
- [2. 媽呀,Jackson原來是這樣寫JSON的](https://mp.weixin.qq.com/s/p6cwP2BVrC8VxkN-T3uAxg)
- [3. 懂了這些,方敢在簡歷上說會用Jackson寫JSON](https://mp.weixin.qq.com/s/ZHb3P06IC4xElHwJqDepxw)
- [4. JSON字串是如何被解析的?JsonParser瞭解一下](https://mp.weixin.qq.com/s/syAOETfEawiGItaQO35mLA)
- [5. JsonFactory工廠而已,還蠻有料,這是我沒想到的](https://mp.weixin.qq.com/s/0ZaDYb_ueFLbvOf3FbetfQ)
- [6. 二十不惑,ObjectMapper使用也不再迷惑](https://mp.weixin.qq.com/s/VYy1QVeFLRkciymFHueb5w)
- [7. Jackson用樹模型處理JSON是必備技能,不信你看](https://mp.weixin.qq.com/s/hPRdt-6sHt4rZaW2_jhdWQ)
【資料校驗Bean Validation】系列:
- [1. 不吹不擂,第一篇就能提升你對Bean Validation資料校驗的認知](https://mp.weixin.qq.com/s/g04HMhrjbvbPn1Mb9JYa5g)
- [2. Bean Validation宣告式校驗方法的引數、返回值](https://mp.weixin.qq.com/s/-KeOCq2rsXCvrqD8HYHSpQ)
- [3. 站在使用層面,Bean Validation這些標準介面你需要爛熟於胸](https://mp.weixin.qq.com/s/MQjXG0cg8domRtwf3ArvHw)
- [4. Validator校驗器的五大核心元件,一個都不能少](https://mp.weixin.qq.com/s/jzOv67ZTSx2rByj0aeUTgw)
- [5. Bean Validation宣告式驗證四大級別:欄位、屬性、容器元素、類](https://mp.weixin.qq.com/s/6_7gZ9jmQcDSRiARO6D-yw)
- [6. 自定義容器型別元素驗證,類級別驗證(多欄位聯合驗證)](https://mp.weixin.qq.com/s/MN-_JCGnsEWpPJs9xQ_qZA)
【新特性】系列:
- [Spring Cloud 2020.0.0正式釋出,再見了Netflix](https://mp.weixin.qq.com/s/FnNJEVa5n-TioifE2mcqIw)
- [IntelliJ IDEA 2020.3正式釋出,年度最後一個版本很講武德](https://mp.weixin.qq.com/s/vNnfKEGRm7R3PN_lCtXJDA)
- [IntelliJ IDEA 2020.2正式釋出,諸多亮點總有幾款能助你提效](https://mp.weixin.qq.com/s/8voJSbmcBbdfNUCUBIcKcA)
- [IntelliJ IDEA 2020.1正式釋出,你要的Almost都在這!]()
- [Spring Framework 5.3.0正式釋出,在雲原生路上繼續發力](https://mp.weixin.qq.com/s/Sw6EqAY0DmF-p2qPoaetUg)
- [Spring Boot 2.4.0正式釋出,全新的配置檔案載入機制(不向下相容)](https://mp.weixin.qq.com/s/KywpJkLDHZbZTxUf4WFxhw)
- [Spring改變版本號命名規則:此舉對非英語國家很友好](https://mp.weixin.qq.com/s/ZoUG9h1TndW2QpnPyGeIQA)
- [JDK15正式釋出,劃時代的ZGC同時宣佈轉正](https://mp.weixin.qq.com/s/3QaiUGzj5nW2N4Aipm47PQ)
【程式人生】系列:
- [螞蟻金服上市了,我不想努力了](https://mp.weixin.qq.com/s/oEShE0fiHSGG8D89NRQYGw)
- [如果程式設計師和產品經理都用凡爾賽文學對話......](https://mp.weixin.qq.com/s/SZUJ0sy4vM7UH10pk6NM3g)
- [程式人生 | 春風得意馬蹄疾,一日看盡長安花](https://mp.weixin.qq.com/s/PGIFtpI7aZaxY7es0F6C6Q)
還有諸如【Spring配置類】【Spring-static關鍵字】【Spring資料繫結】【Spring Cloud Netflix】【Feign】【Ribbon】【Hystrix】...更多原創專欄,關注`BAT的烏托邦`回覆`專欄`二字即可全部獲取,也可加我`fsx1056342982`,交個朋友。
> 有些**已完結**,有些**連載中**。我是A哥(YourBatman),咱們下期見