今天的菜品是這樣的:
怎樣把許多小字符串合并成一個(gè)大的字符串。
太長(zhǎng)不看版
- 可以用String.join()方法將字符串的List或數(shù)組拼接成一個(gè)大字符串舆蝴,并指定分隔符谦絮。
- 也可以手動(dòng)創(chuàng)建StringJoiner對(duì)象,指定分隔符洁仗、前綴和后綴层皱。
- 如果需要先對(duì)字符串進(jìn)行處理,可以將List或數(shù)組轉(zhuǎn)成Stream赠潦,處理后再利用Collectors.joining()方法進(jìn)行合并叫胖。
- 避免在循環(huán)中使用+操作符進(jìn)行字符串拼接
String.join()方法
如果想要合并的字符串在一個(gè)列表、數(shù)組或其他可迭代對(duì)象中她奥,那么合并它們最快的方法就是使用String.join()靜態(tài)方法瓮增。這一個(gè)API可以說(shuō)是千呼萬(wàn)喚才在jdk8中“始出來(lái)”,因?yàn)槠渌Z(yǔ)言很早就支持這一方便的特性哩俭。示例如下:
List<String> list = List.of("Java", "is", "very", "cool"); // 注意這個(gè)api是jdk9之后引入的
final String join = String.join(",", list);
System.out.println(join); // Java,is,very,cool
String.join()方法的第一個(gè)參數(shù)是分隔符绷跑,即字符串拼接時(shí)連接各個(gè)小字符串的字符,第二個(gè)參數(shù)是可迭代對(duì)象或者不定長(zhǎng)參數(shù)携茂。因此該API支持?jǐn)?shù)組以及List、Set等各種可迭代對(duì)象诅岩,也可以按不定長(zhǎng)的方式使用:
final String join = String.join(",", "Java", "is", "very", "cool");
System.out.println(join); // Java,is,very,cool
StringJoiner
/* String.join()源碼 */
public static String join(CharSequence delimiter, CharSequence... elements) {
Objects.requireNonNull(delimiter);
Objects.requireNonNull(elements);
StringJoiner joiner = new StringJoiner(delimiter);
for (CharSequence cs: elements) {
joiner.add(cs);
}
return joiner.toString();
}
public static String join(CharSequence delimiter,
Iterable<? extends CharSequence> elements) {
Objects.requireNonNull(delimiter);
Objects.requireNonNull(elements);
StringJoiner joiner = new StringJoiner(delimiter);
for (CharSequence cs: elements) {
joiner.add(cs);
}
return joiner.toString();
}
通過(guò)String.join()兩個(gè)重載方法的源碼我們發(fā)現(xiàn)讳苦,String.join()方法是通過(guò)創(chuàng)建StringJoiner對(duì)象實(shí)現(xiàn)的带膜,該類同樣也是在jdk8版本引入的。
有時(shí)候我們也可以主動(dòng)創(chuàng)建StringJoiner類來(lái)實(shí)現(xiàn)字符串的合并鸳谜,如在合并結(jié)果需要前后綴的情況下:
StringJoiner joiner = new StringJoiner("-", "(", ")");
List<String> list = List.of("Java", "is", "very", "cool");
list.forEach(joiner::add);
System.out.println(joiner.toString());
Stream收集器的Collectors.joining()
有時(shí)候我們需要對(duì)原字符串列表進(jìn)行一定處理后再進(jìn)行拼接膝藕,這時(shí)我們就可以用Stream的collect方法直接對(duì)處理后的字符串進(jìn)行拼接,示例如下:
List<String> list = List.of("Java", "is", "very", "cool");
final String result = list.stream().map(s -> s + "abc").collect(Collectors.joining("-"));
System.out.println(result); // Javaabc-isabc-veryabc-coolabc
+號(hào)與StringBuilder
如果只是要簡(jiǎn)單連接一些字符串咐扭,一般直接使用+操作符就足夠完成任務(wù)了芭挽。但是我們需要意識(shí)到,在使用+操作符對(duì)大量字符串進(jìn)行拼接的時(shí)候蝗肪,這種連接的效率是很低的袜爪。
因?yàn)槭褂?操作符拼接字符串是Java內(nèi)置的一種操作符重載的行為,在編譯階段薛闪,非字面量字符串進(jìn)行拼接時(shí)辛馆,會(huì)被編譯器改寫為通過(guò)StringBuilder的append方法進(jìn)行拼接。如果在循環(huán)結(jié)構(gòu)中使用+進(jìn)行字符串拼接豁延,則會(huì)產(chǎn)生大量的StringBuilder對(duì)象昙篙,降低整個(gè)程序運(yùn)行效率。因此我們應(yīng)該避免在循環(huán)結(jié)構(gòu)中使用加號(hào)進(jìn)行字符串拼接诱咏,改用String.join方法或者手動(dòng)在循環(huán)外創(chuàng)建StringBuilder對(duì)象苔可。
String str = "";
// 錯(cuò)誤!4焚辅!不能在循環(huán)中使用+或+=進(jìn)行字符串拼接!!!
//for (s: list) {
// str += s;
//}
// 方法1,推薦
str = String.join("", str);
// 方法2硕并,相對(duì)麻煩
StringBuilder sb = new StringBuilder();
list.forEach(sb::append);
str = sb.toString();
// 方法3法焰,相對(duì)麻煩
StringJoiner sj = new StringJoiner("");
list.forEach(sj::add);
str = sj.toString();