GitHub 1.3k Star 的Java工程師成神之路 ,不來了解一下嗎?html
在爲何阿里巴巴不建議在for循環中使用」+」進行字符串拼接一文中,咱們介紹了幾種Java中字符串拼接的方式,以及優缺點。其中還有一個重要的拼接方式我沒有介紹,那就是Java 8中提供的StringJoiner ,本文就來介紹一下這個字符串拼接的新兵。java
若是你想知道一共有多少種方法能夠進行字符串拼接,教你一個簡單的辦法,在Intellij IDEA中,定義一個Java Bean,而後嘗試使用快捷鍵自動生成一個toString方法,IDEA會提示多種toString生成策略可供選擇。git
目前我使用的IDEA的toString生成策略默認的是使用JDK 1.8提供的StringJoiner。github
StringJoiner是java.util包中的一個類,用於構造一個由分隔符分隔的字符序列(可選),而且能夠從提供的前綴開始並以提供的後綴結尾。雖然這也能夠在StringBuilder類的幫助下在每一個字符串以後附加分隔符,但StringJoiner提供了簡單的方法來實現,而無需編寫大量代碼。api
StringJoiner類共有2個構造函數,5個公有方法。其中最經常使用的方法就是add方法和toString方法,相似於StringBuilder中的append方法和toString方法。安全
StringJoiner的用法比較簡單,下面的代碼中,咱們使用StringJoiner進行了字符串拼接。oracle
public class StringJoinerTest {
public static void main(String[] args) {
StringJoiner sj = new StringJoiner("Hollis");
sj.add("hollischuang");
sj.add("Java乾貨");
System.out.println(sj.toString());
StringJoiner sj1 = new StringJoiner(":","[","]");
sj1.add("Hollis").add("hollischuang").add("Java乾貨");
System.out.println(sj1.toString());
}
}
複製代碼
以上代碼輸出結果:app
hollischuangHollisJava乾貨
[Hollis:hollischuang:Java乾貨]
複製代碼
值得注意的是,當咱們StringJoiner(CharSequence delimiter)
初始化一個StringJoiner
的時候,這個delimiter
實際上是分隔符,並非可變字符串的初始值。函數
StringJoiner(CharSequence delimiter,CharSequence prefix,CharSequence suffix)
的第二個和第三個參數分別是拼接後的字符串的前綴和後綴。性能
介紹了簡單的用法以後,咱們再來看看這個StringJoiner的原理,看看他究竟是如何實現的。主要看一下add方法:
public StringJoiner add(CharSequence newElement) {
prepareBuilder().append(newElement);
return this;
}
private StringBuilder prepareBuilder() {
if (value != null) {
value.append(delimiter);
} else {
value = new StringBuilder().append(prefix);
}
return value;
}
複製代碼
看到了一個熟悉的身影——StringBuilder ,沒錯,StringJoiner其實就是依賴StringBuilder實現的,在爲何阿里巴巴不建議在for循環中使用」+」進行字符串拼接中咱們介紹過StringBuilder的實現原理,本文不在贅述。
當咱們發現StringJoiner實際上是經過StringBuilder實現以後,咱們大概就能夠猜到,他的性能損耗應該和直接使用StringBuilder差很少!
在瞭解了StringJoiner的用法和原理後,可能不少讀者就會產生一個疑問,明明已經有一個StringBuilder了,爲何Java 8中還要定義一個StringJoiner呢?到底有什麼好處呢?
若是讀者足夠了解Java 8的話,或許能夠猜出個大概,這確定和Stream有關。
做者也在Java doc中找到了答案:
A StringJoiner may be employed to create formatted output from a Stream using Collectors.joining(CharSequence)
試想,在Java中,若是咱們有這樣一個List:
List<String> list = ImmutableList.of("Hollis","hollischuang","Java乾貨");
複製代碼
若是咱們想要把他拼接成一個如下形式的字符串:
Hollis,hollischuang,Java乾貨
複製代碼
能夠經過如下方式:
StringBuilder builder = new StringBuilder();
if (!list.isEmpty()) {
builder.append(list.get(0));
for (int i = 1, n = list.size(); i < n; i++) {
builder.append(",").append(list.get(i));
}
}
builder.toString();
複製代碼
還可使用:
list.stream().reduce(new StringBuilder(), (sb, s) -> sb.append(s).append(','), StringBuilder::append).toString();
複製代碼
可是輸出結果稍有些不一樣,須要進行二次處理:
Hollis,hollischuang,Java乾貨,
複製代碼
還可使用"+"進行拼接:
list.stream().reduce((a,b)->a + "," + b).toString();
複製代碼
以上幾種方式,要麼是代碼複雜,要麼是性能不高,或者沒法直接獲得想要的結果。
爲了知足相似這樣的需求,Java 8中提供的StringJoiner就派上用場了。以上需求只須要一行代碼:
list.stream().collect(Collectors.joining(":"))
複製代碼
便可。上面用的表達式中,Collectors.joining的源代碼以下:
public static Collector<CharSequence, ?, String> joining(CharSequence delimiter,
CharSequence prefix,
CharSequence suffix) {
return new CollectorImpl<>(
() -> new StringJoiner(delimiter, prefix, suffix),
StringJoiner::add, StringJoiner::merge,
StringJoiner::toString, CH_NOID);
}
複製代碼
其實現原理就是藉助了StringJoiner。
固然,或許在Collector
中直接使用StringBuilder
彷佛也能夠實現相似的功能,只不過稍微麻煩一些。因此,Java 8中提供了StringJoiner
來豐富Stream
的用法。
並且StringJoiner
也能夠方便的增長前綴和後綴,好比咱們但願獲得的字符串是[Hollis,hollischuang,Java乾貨]
而不是Hollis,hollischuang,Java
乾貨的話,StringJoiner的優點就更加明顯了。
本文介紹了Java 8中提供的可變字符串類——StringJoiner,能夠用於字符串拼接。
StringJoiner實際上是經過StringBuilder實現的,因此他的性能和StringBuilder差很少,他也是非線程安全的。
若是平常開發中中,須要進行字符串拼接,如何選擇?
一、若是隻是簡單的字符串拼接,考慮直接使用"+"便可。
二、若是是在for循環中進行字符串拼接,考慮使用StringBuilder
和StringBuffer
。
三、若是是經過一個List
進行字符串拼接,則考慮使用StringJoiner
。
GitHub 1.3k Star 的Java工程師成神之路 ,不來了解一下嗎?
GitHub 1.3k Star 的Java工程師成神之路 ,真的不來了解一下嗎?
GitHub 1.3k Star 的Java工程師成神之路 ,真的肯定不來了解一下嗎?