不要再用 StringBuilder 拼接字符串了,來試試字符串模板

引言

字符串操作是 Java 中使用最頻繁的操作颈嚼,沒有之一毛秘。其中非常常見的操作之一就是對字符串的組織,由于常見所以就衍生了多種方案阻课。比如我們要實現(xiàn) x + y = ?叫挟,方案有如下幾種

使用 + 進行字符串拼接

String s = x + " + " + y + " = " + (x + y);

使用 StringBuilder

String s = new StringBuilder()

.append(x)

.append(" + ")

.append(y)

.append(" = ")

.append(x + y)

.toString()

String::format 和 String::formatted 將格式字符串從參數(shù)中分離出來

String s = String.format("%2$d + %1$d = %3$d", x, y, x + y);

or

String s = "%2$d + %1$d = %3$d".formatted(x, y, x + y);

java.text.MessageFormat

String s = MessageFormat.format("{0} + {1} = {2}", x,y, x + y);

這四種方案雖然都可以解決,但很遺憾的是他們或多或少都有點兒缺陷限煞,尤其是面對 Java 13 引入的文本塊(Java 13 新特性—文本塊)更是束手無措抹恳。

字符串模板

為了簡化字符串的構(gòu)造和格式化,Java 21 引入字符串模板功能晰骑,該特性主要目的是為了提高在處理包含多個變量和復雜格式化要求的字符串時的可讀性和編寫效率适秩。

它的設(shè)計目標是:

通過簡單的方式表達混合變量的字符串,簡化 Java 程序的編寫硕舆。

提高混合文本和表達式的可讀性秽荞,無論文本是在單行源代碼中(如字符串字面量)還是跨越多行源代碼(如文本塊)。

通過支持對模板及其嵌入式表達式的值進行驗證和轉(zhuǎn)換抚官,提高根據(jù)用戶提供的值組成字符串并將其傳遞給其他系統(tǒng)(如構(gòu)建數(shù)據(jù)庫查詢)的 Java 程序的安全性扬跋。

允許 Java 庫定義字符串模板中使用的格式化語法(java.util.Formatter ),從而保持靈活性凌节。

簡化接受以非 Java 語言編寫的字符串(如 SQL钦听、XML 和 JSON)的 API 的使用。

支持創(chuàng)建由字面文本和嵌入式表達式計算得出的非字符串值倍奢,而無需通過中間字符串表示朴上。

該特性處理字符串的新方法稱為:Template Expressions,即:模版表達式卒煞。它是 Java 中的一種新型表達式痪宰,不僅可以執(zhí)行字符串插值,還可以編程,從而幫助開發(fā)人員安全高效地組成字符串衣撬。此外乖订,模板表達式并不局限于組成字符串——它們可以根據(jù)特定領(lǐng)域的規(guī)則將結(jié)構(gòu)化文本轉(zhuǎn)化為任何類型的對象。

STR 模板處理器

STR 是 Java 平臺定義的一種模板處理器具练。它通過用表達式的值替換模板中的每個嵌入表達式來執(zhí)行字符串插值乍构。使用 STR 的模板表達式的求值結(jié)果是一個字符串。

STR 是一個公共靜態(tài) final 字段扛点,會自動導入到每個 Java 源文件中哥遮。

我們先看一個簡單的例子:

@Test

public void STRTest() {

String sk = "死磕 Java 新特性";

String str1 = STR."{sk},就是牛";

System.out.println(str1);

}

// 結(jié)果.....

死磕 Java 新特性占键,就是牛

上面的 STR."{sk}昔善,就是牛" 就是一個模板表達式,它主要包含了三個部分:

模版處理器:STR

包含內(nèi)嵌表達式({blog})的模版

通過.把前面兩部分組合起來畔乙,形式如同方法調(diào)用

當模版表達式運行的時候,模版處理器會將模版內(nèi)容與內(nèi)嵌表達式的值組合起來翩概,生成結(jié)果牲距。

這個例子只是 STR模版處理器一個很簡單的功能,它可以做的事情有很多钥庇。

數(shù)學運算

比如上面的 x + y = ?:

@Test

public void STRTest() {

int x = 1,y =2;

String str = STR."{x} + {y} = {x + y}";

System.out.println(str);

}

這種寫法是不是簡單明了了很多牍鞠?

調(diào)用方法

STR模版處理器還可以調(diào)用方法,比如:

ini 代碼解讀復制代碼String str = STR."今天是:{?LocalDate.now()} ";

當然也可以調(diào)用我們自定義的方法:

@Test

public void STRTest() {

String str = STR."{getSkStr()},就是牛";

System.out.println(str);

}

public String getSkStr() {

return "死磕 Java 新特性";

}

訪問成員變量

STR模版處理器還可以訪問成員變量评姨,比如:

public record User(String name,Integer age) {

}

@Test

public void STRTest() {

User user = new User("大明哥",18);

String str = STR."{user.name()}今年{user.age()}";

System.out.println(str);

}

需要注意的是难述,字符串模板表達式中的嵌入表達式數(shù)量沒有限制,它從左到右依次求值吐句,就像方法調(diào)用表達式中的參數(shù)一樣胁后。例如:

@Test

public void STRTest() {

int i = 0;

String str = STR."{i++},{i++},{i++},{i++},{i++}";

System.out.println(str);

}

// 結(jié)果......

0,1,2,3,4

同時,表達式中也可以嵌入表達式:

@Test

public void STRTest() {

String name = "大明哥";

String sk = "死磕 Java 新特性";

String str = STR."{name}的{STR."{sk},就是牛..."}";

System.out.println(str);

}

// 結(jié)果......

大明哥的死磕 Java 新特性,就是牛...

但是這種嵌套的方式會比較復雜嗦枢,容易搞混攀芯,一般不推薦。

多行模板表達式

為了解決多行字符串處理的復雜性文虏,Java 13 引入文本塊(Java 13 新特性—文本塊)侣诺,它是使用三個雙引號(""")來標記字符串的開始和結(jié)束,允許字符串跨越多行而無需顯式的換行符或字符串連接氧秘。如下:

String html = """

<html>

<body>

http://skjava.com

<ul>

<li>死磕 Java 新特性</li>

<li>死磕 Java 并發(fā)</li>

<li>死磕 Netty</li>

<li>死磕 Redis</li>

</ul>

</body>

</html>

""";

如果字符串模板表達式年鸳,我們就只能拼接這串字符串了,這顯得有點兒繁瑣和麻煩丸相。而字符串模版表達式也支持多行字符串處理搔确,我們可以利用它來方便的組織html、json、xml等字符串內(nèi)容妥箕,比如這樣:

@Test

public void STRTest() {

String title = "死磕 Java - 一站式 Java 學習平臺";

String sk1 = "死磕 Java 新特性";

String sk2 = "死磕 Java 并發(fā)";

String sk3 = "死磕 Netty";

String sk4 = "死磕 Redis";

String html = STR."""

<html>

<body>

<h2>{title}</h2>

<ul>

<li>{sk1}</li>

<li>{sk2}</li>

<li>{sk3}</li>

<li>{sk4}</li>

</ul>

</body>

</html>

""";

System.out.println(html);

}

如果決定定義四個 sk 變量麻煩滥酥,可以整理為一個集合,然后調(diào)用方法生成 <li> 標簽畦幢。

FMT 模板處理器

FMT 是 Java 定義的另一種模板處理器坎吻。它除了與STR模版處理器一樣提供插值能力之外,還提供了左側(cè)的格式化處理宇葱。

Java 版本更新類型JEP更新內(nèi)容Java 17第一次預覽JEP 406引入模式匹配的 Swith 表達式作為預覽特性瘦真。Java 18第二次預覽JEP 420對其做了改進和細微調(diào)整Java 19第三次預覽JEP 427進一步優(yōu)化模式匹配的 Swith 表達式Java 20第四次預覽JEP 433Java 21正式特性JEP 441成為正式特性

如果使用 STR 模板處理器,代碼如下:

@Test

public void STRTest() {

SwitchHistory[] switchHistories = new SwitchHistory[]{

new SwitchHistory("Java 17","第一次預覽","JEP 406","引入模式匹配的 Swith 表達式作為預覽特性黍瞧。"),

new SwitchHistory("Java 18","第二次預覽","JEP 420","對其做了改進和細微調(diào)整"),

new SwitchHistory("Java 19","第三次預覽","JEP 427","進一步優(yōu)化模式匹配的 Swith 表達式"),

new SwitchHistory("Java 20","第四次預覽","JEP 433",""),

new SwitchHistory("Java 21","正式特性","JEP 441","成為正式特性"),

};

String history = STR."""

Java 版本 更新類型 JEP 更新內(nèi)容

{switchHistories[0].javaVersion()} {switchHistories[0].updateType()} {switchHistories[0].jep()} {switchHistories[0].content()}

{switchHistories[1].javaVersion()} {switchHistories[1].updateType()} {switchHistories[1].jep()} {switchHistories[1].content()}

{switchHistories[2].javaVersion()} {switchHistories[2].updateType()} {switchHistories[2].jep()} {switchHistories[2].content()}

{switchHistories[3].javaVersion()} {switchHistories[3].updateType()} {switchHistories[3].jep()} {switchHistories[3].content()}

{switchHistories[4].javaVersion()} {switchHistories[4].updateType()} {switchHistories[4].jep()} {switchHistories[4].content()}

""";

System.out.println(history);

}

得到的效果是這樣的:

版本 更新類型 JEP 更新內(nèi)容

Java 17 第一次預覽 JEP 406 引入模式匹配的 Swith 表達式作為預覽特性诸尽。

Java 18 第二次預覽 JEP 420 對其做了改進和細微調(diào)整

Java 19 第三次預覽 JEP 427 進一步優(yōu)化模式匹配的 Swith 表達式

Java 20 第四次預覽 JEP 433

Java 21 正式特性 JEP 441 成為正式特性

是不是很丑?完全對不齊印颤,沒法看您机。為了解決這個問題,就可以采用FMT模版處理器年局,在每一列左側(cè)定義格式:

@Test

public void STRTest() {

SwitchHistory[] switchHistories = new SwitchHistory[]{

new SwitchHistory("Java 17","第一次預覽","JEP 406","引入模式匹配的 Swith 表達式作為預覽特性际看。"),

new SwitchHistory("Java 18","第二次預覽","JEP 420","對其做了改進和細微調(diào)整"),

new SwitchHistory("Java 19","第三次預覽","JEP 427","進一步優(yōu)化模式匹配的 Swith 表達式"),

new SwitchHistory("Java 20","第四次預覽","JEP 433",""),

new SwitchHistory("Java 21","正式特性","JEP 441","成為正式特性"),

};

String history = FMT."""

Java 版本 更新類型 JEP 更新內(nèi)容

%-10s{switchHistories[0].javaVersion()} %-9s{switchHistories[0].updateType()} %-10s{switchHistories[0].jep()} %-20s{switchHistories[0].content()}

%-10s{switchHistories[1].javaVersion()} %-9s{switchHistories[1].updateType()} %-10s{switchHistories[1].jep()} %-20s{switchHistories[1].content()}

%-10s{switchHistories[2].javaVersion()} %-9s{switchHistories[2].updateType()} %-10s{switchHistories[2].jep()} %-20s{switchHistories[2].content()}

%-10s{switchHistories[3].javaVersion()} %-9s{switchHistories[3].updateType()} %-10s{switchHistories[3].jep()} %-20s{switchHistories[3].content()}

%-10s{switchHistories[4].javaVersion()} %-9s{switchHistories[4].updateType()} %-10s{switchHistories[4].jep()} %-20s{switchHistories[4].content()}

""";

System.out.println(history);

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市矢否,隨后出現(xiàn)的幾起案子仲闽,更是在濱河造成了極大的恐慌,老刑警劉巖僵朗,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赖欣,死亡現(xiàn)場離奇詭異,居然都是意外死亡验庙,警方通過查閱死者的電腦和手機顶吮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來壶谒,“玉大人云矫,你說我怎么就攤上這事『共耍” “怎么了让禀?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長陨界。 經(jīng)常有香客問我巡揍,道長,這世上最難降的妖魔是什么菌瘪? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任腮敌,我火速辦了婚禮阱当,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘糜工。我一直安慰自己弊添,他們只是感情好,可當我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布捌木。 她就那樣靜靜地躺著油坝,像睡著了一般。 火紅的嫁衣襯著肌膚如雪刨裆。 梳的紋絲不亂的頭發(fā)上澈圈,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天,我揣著相機與錄音帆啃,去河邊找鬼瞬女。 笑死,一個胖子當著我的面吹牛努潘,可吹牛的內(nèi)容都是我干的诽偷。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼慈俯,長吁一口氣:“原來是場噩夢啊……” “哼渤刃!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起贴膘,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎略号,沒想到半個月后刑峡,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡玄柠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年突梦,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片羽利。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡宫患,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出这弧,到底是詐尸還是另有隱情娃闲,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布匾浪,位于F島的核電站皇帮,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏蛋辈。R本人自食惡果不足惜属拾,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧渐白,春花似錦尊浓、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至托酸,卻和暖如春褒颈,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背励堡。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工谷丸, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人应结。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓刨疼,卻偏偏與公主長得像,于是被迫代替她去往敵國和親鹅龄。 傳聞我的和親對象是個殘疾皇子揩慕,可洞房花燭夜當晚...
    茶點故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內(nèi)容