最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java代碼中4種字符串拼接方式分析

 更新時(shí)間:2022年02月14日 11:37:18   作者:雪中亮  
本文主要介紹了Java代碼中4種字符串拼接方式分析,主要介紹了“+”號(hào)、StringBuilder、StringJoiner、String#join,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

本文研討的字符串拼接方式為以下4種:“+”號(hào)、StringBuilder、StringJoiner、String#join,對(duì)比分析及探討最佳實(shí)踐。

結(jié)論

后面內(nèi)容比較枯燥,所以先說(shuō)結(jié)論:

  • 本文研討的字符串拼接方式為以下4種:“+”號(hào)、StringBuilder、StringJoiner、String#join
  • 在簡(jiǎn)單的字符串拼接場(chǎng)景中「如:"a" + "b" + "c"」,以上四種方式性能無(wú)明顯差異。
  • 在循環(huán)字符串拼接的場(chǎng)景下,使用“+”號(hào)性能最低,其他三種方式性能也無(wú)明顯差異,但是根據(jù)驗(yàn)證結(jié)果可粗淺發(fā)現(xiàn),指定初始容量的StringBuilder效率最高。當(dāng)然不光考慮性能,也要考慮垃圾回收效率的問(wèn)題,避免OOM。
  • 本文最后補(bǔ)充對(duì)比了StringBuffer,在無(wú)爭(zhēng)搶共享資源的場(chǎng)景下,StringBuffer性能并未明顯變差。

最佳實(shí)踐

  • 阿里巴巴Java開(kāi)發(fā)手冊(cè)-日志規(guī)約「5」可進(jìn)行優(yōu)化:使用占位符的形式可讀性、便捷性不佳,可考慮使用Lambda,延遲字符串的拼接,且使用更加便利。
  • 阿里巴巴Java開(kāi)發(fā)手冊(cè)-OOP 規(guī)約「23」可進(jìn)行優(yōu)化:循環(huán)拼接時(shí)須使用StringBuilder;在拼接大量的大容量字符串時(shí),使用StringBuilder盡量指定初始容量。
  • 簡(jiǎn)單的字符串拼接可用任意方式,推薦直接使用“+”號(hào)拼接,可讀性最優(yōu)。
  • 盡量使用JDK等直接提供的特性「如“+”號(hào)拼接字符串,Synchronized關(guān)鍵詞等」,因?yàn)榫幾g器+JVM會(huì)持續(xù)對(duì)此進(jìn)行優(yōu)化,JDK升級(jí)即可獲得更大的收益。除非有明確的理由可以自行實(shí)現(xiàn)類似的功能。
  • 在需要考慮線程安全的場(chǎng)景可以考慮使用StringBuffer進(jìn)行字符串拼接,不過(guò)一般來(lái)說(shuō)沒(méi)有這種需求,故不應(yīng)該使用StringBuffer,避免增加復(fù)雜性。

分析過(guò)程

環(huán)境

  • 系統(tǒng): windows 10 21H1
  • JDK: OpenJDK 1.8.0_302

分析用示例代碼:

@Slf4j
public class StringConcat {

? ? @SneakyThrows
? ? public static void main(String[] args) {
? ? ? ? log.info("java虛擬機(jī)預(yù)熱開(kāi)始");
? ? ? ? String[] strs = new String[6000000];
? ? ? ? for (int i = 0; i < strs.length; i++) {
? ? ? ? ? ? strs[i] = id();
? ? ? ? }
? ? ? ? loopStringJoiner(strs);
? ? ? ? loopStringJoin(strs);
? ? ? ? loopStringBuilder(strs);
? ? ? ? log.info("java虛擬機(jī)預(yù)熱結(jié)束");
? ? ? ? Thread.sleep(1000);
? ? ? ? log.info("開(kāi)始測(cè)試:");

? ? ? ? Thread.sleep(1000);
? ? ? ? Stopwatch stopwatchLoopPlus = Stopwatch.createStarted();
// ? ? ? ?loopPlus(strs);
? ? ? ? log.info("loop-plus: " + stopwatchLoopPlus.elapsed(TimeUnit.MILLISECONDS));

? ? ? ? Thread.sleep(1000);
? ? ? ? Stopwatch stopwatchLoopStringBuilderCapacity = Stopwatch.createStarted();
? ? ? ? loopStringBuilderCapacity(strs);
? ? ? ? log.info("loop-stringBuilderCapacity: " + stopwatchLoopStringBuilderCapacity.elapsed(TimeUnit.MILLISECONDS));

? ? ? ? Thread.sleep(1000);
? ? ? ? Stopwatch stopwatchLoopStringBuilder = Stopwatch.createStarted();
? ? ? ? loopStringBuilder(strs);
? ? ? ? log.info("loop-stringBuilder: " + stopwatchLoopStringBuilder.elapsed(TimeUnit.MILLISECONDS));

? ? ? ? Thread.sleep(1000);
? ? ? ? Stopwatch stopwatchLoopJoin = Stopwatch.createStarted();
? ? ? ? loopStringJoin(strs);
? ? ? ? log.info("loop-String.join: " + stopwatchLoopJoin.elapsed(TimeUnit.MILLISECONDS));

? ? ? ? Thread.sleep(1000);
? ? ? ? Stopwatch stopwatchLoopStringJoiner = Stopwatch.createStarted();
? ? ? ? loopStringJoiner(strs);
? ? ? ? log.info("loop-stringJoiner: " + stopwatchLoopStringJoiner.elapsed(TimeUnit.MILLISECONDS));

? ? ? ? Thread.sleep(1000);
? ? ? ? Stopwatch stopwatchSimplePlus = Stopwatch.createStarted();
? ? ? ? for (int i = 0; i < 500000; i++) {
? ? ? ? ? ? simplePlus(id(), id(), id());
? ? ? ? }
? ? ? ? log.info("simple-Plus: " + stopwatchSimplePlus.elapsed(TimeUnit.MILLISECONDS));

? ? ? ? Thread.sleep(1000);
? ? ? ? Stopwatch stopwatchSimpleStringBuilder = Stopwatch.createStarted();
? ? ? ? for (int i = 0; i < 500000; i++) {
? ? ? ? ? ? simpleStringBuilder(id(), id(), id());
? ? ? ? }
? ? ? ? log.info("simple-StringBuilder: " + stopwatchSimpleStringBuilder.elapsed(TimeUnit.MILLISECONDS));

? ? ? ? Thread.sleep(1000);
? ? ? ? Stopwatch stopwatchSimpleStringBuffer = Stopwatch.createStarted();
? ? ? ? for (int i = 0; i < 500000; i++) {
? ? ? ? ? ? simpleStringBuffer(id(), id(), id());
? ? ? ? }
? ? ? ? log.info("simple-StringBuffer: " + stopwatchSimpleStringBuffer.elapsed(TimeUnit.MILLISECONDS));

? ? }

? ? private static String loopPlus(String[] strs) {
? ? ? ? String str = "";
? ? ? ? for (String s : strs) {
? ? ? ? ? ? str = str + "+" + s;
? ? ? ? }
? ? ? ? return str;
? ? }

? ? private static String loopStringBuilder(String[] strs) {
? ? ? ? StringBuilder str = new StringBuilder();
? ? ? ? for (String s : strs) {
? ? ? ? ? ? str.append("+");
? ? ? ? ? ? str.append(s);
? ? ? ? }
? ? ? ? return str.toString();
? ? }

? ? private static String loopStringBuilderCapacity(String[] strs) {
? ? ? ? StringBuilder str = new StringBuilder(strs[0].length() * strs.length);
? ? ? ? for (String s : strs) {
? ? ? ? ? ? str.append("+");
? ? ? ? ? ? str.append(s);
? ? ? ? }
? ? ? ? return str.toString();
? ? }

? ? private static String loopStringJoin(String[] strs) {
? ? ? ? StringJoiner joiner = new StringJoiner("+");
? ? ? ? for (String str : strs) {
? ? ? ? ? ? joiner.add(str);
? ? ? ? }
? ? ? ? return joiner.toString();
? ? }

? ? private static String loopStringJoiner(String[] strs) {
? ? ? ? return String.join("+", strs);
? ? }

? ? private static String simplePlus(String a, String b, String c) {
? ? ? ? return a + "+" + b + "+" + c;
? ? }

? ? private static String simpleStringBuilder(String a, String b, String c) {
? ? ? ? StringBuilder builder = new StringBuilder();
? ? ? ? builder.append(a);
? ? ? ? builder.append("+");
? ? ? ? builder.append(b);
? ? ? ? builder.append("+");
? ? ? ? builder.append(c);
? ? ? ? return builder.toString();
? ? }

? ? private static String simpleStringBuffer(String a, String b, String c) {
? ? ? ? StringBuffer buffer = new StringBuffer();
? ? ? ? buffer.append(a);
? ? ? ? buffer.append("+");
? ? ? ? buffer.append(b);
? ? ? ? buffer.append("+");
? ? ? ? buffer.append(c);
? ? ? ? return buffer.toString();
? ? }

? ? private static String id() {
? ? ? ? return UUID.randomUUID().toString();
? ? }

}

結(jié)果及總結(jié)

- java虛擬機(jī)預(yù)熱開(kāi)始
- java虛擬機(jī)預(yù)熱結(jié)束
- 開(kāi)始測(cè)試:
- loop-plus: 執(zhí)行超時(shí)
- loop-stringBuilderCapacity: 285
- loop-stringBuilder: 1968
- loop-String.join: 1313
- loop-stringJoiner: 1238
- simple-Plus: 812
- simple-StringBuilder: 840
- simple-StringBuffer: 857

  • 多次測(cè)試,可發(fā)現(xiàn)在字符串循環(huán)拼接場(chǎng)景下,直接使用“+”號(hào)性能最低,有初始容量的StringBuilder性能最高,其他方式性能均沒(méi)有太大差異。
  • 多次測(cè)試,可發(fā)現(xiàn)在字符串簡(jiǎn)單拼接場(chǎng)景下,使用“+”號(hào)、StringBuilder、StringBuffer性能差距在5%左右,可理解為測(cè)試誤差,可認(rèn)為三種方式性能一致。

代碼及結(jié)果分析

1. StringBuilder與StringBuffer對(duì)比

在無(wú)爭(zhēng)搶共享資源的場(chǎng)景下,JVM會(huì)使用偏向鎖等方法優(yōu)化,甚至?xí)M(jìn)行鎖消除,使用Synchronized關(guān)鍵詞與否,性能并無(wú)明顯差異。

2. 字節(jié)碼分析

對(duì)比上述#simplePlus和#simpleStringBuilder兩個(gè)方法的字節(jié)碼,可明顯看到兩方法執(zhí)行內(nèi)容基本一致,但是直接使用"+"號(hào)時(shí)處理流程更短,可見(jiàn)編譯器進(jìn)行了深度優(yōu)化,使用優(yōu)化后的字節(jié)碼理論上會(huì)有更高的性能:

? // access flags 0xA
? private static simplePlus(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
? ? // parameter ?a
? ? // parameter ?b
? ? // parameter ?c
? ?L0
? ? LINENUMBER 125 L0
? ? NEW java/lang/StringBuilder
? ? DUP
? ? INVOKESPECIAL java/lang/StringBuilder.<init> ()V
? ? ALOAD 0
? ? INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
? ? LDC "+"
? ? INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
? ? ALOAD 1
? ? INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
? ? LDC "+"
? ? INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
? ? ALOAD 2
? ? INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
? ? INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
? ? ARETURN
? ?L1
? ? LOCALVARIABLE a Ljava/lang/String; L0 L1 0
? ? LOCALVARIABLE b Ljava/lang/String; L0 L1 1
? ? LOCALVARIABLE c Ljava/lang/String; L0 L1 2
? ? MAXSTACK = 2
? ? MAXLOCALS = 3

? // access flags 0xA
? private static simpleStringBuilder(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
? ? // parameter ?a
? ? // parameter ?b
? ? // parameter ?c
? ?L0
? ? LINENUMBER 129 L0
? ? NEW java/lang/StringBuilder
? ? DUP
? ? INVOKESPECIAL java/lang/StringBuilder.<init> ()V
? ? ASTORE 3
? ?L1
? ? LINENUMBER 130 L1
? ? ALOAD 3
? ? ALOAD 0
? ? INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
? ? POP
? ?L2
? ? LINENUMBER 131 L2
? ? ALOAD 3
? ? LDC "+"
? ? INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
? ? POP
? ?L3
? ? LINENUMBER 132 L3
? ? ALOAD 3
? ? ALOAD 1
? ? INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
? ? POP
? ?L4
? ? LINENUMBER 133 L4
? ? ALOAD 3
? ? LDC "+"
? ? INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
? ? POP
? ?L5
? ? LINENUMBER 134 L5
? ? ALOAD 3
? ? ALOAD 2
? ? INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
? ? POP
? ?L6
? ? LINENUMBER 135 L6
? ? ALOAD 3
? ? INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
? ? ARETURN
? ?L7
? ? LOCALVARIABLE a Ljava/lang/String; L0 L7 0
? ? LOCALVARIABLE b Ljava/lang/String; L0 L7 1
? ? LOCALVARIABLE c Ljava/lang/String; L0 L7 2
? ? LOCALVARIABLE builder Ljava/lang/StringBuilder; L1 L7 3
? ? MAXSTACK = 2
? ? MAXLOCALS = 4

到此這篇關(guān)于Java代碼中4種字符串拼接方式分析的文章就介紹到這了,更多相關(guān)Java 字符串拼接內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java動(dòng)態(tài)代理的示例詳解

    Java動(dòng)態(tài)代理的示例詳解

    動(dòng)態(tài)代理指的是,代理類和目標(biāo)類的關(guān)系在程序運(yùn)行的時(shí)候確定的,客戶通過(guò)代理類來(lái)調(diào)用目標(biāo)對(duì)象的方法,是在程序運(yùn)行時(shí)根據(jù)需要?jiǎng)討B(tài)的創(chuàng)建目標(biāo)類的代理對(duì)象。本文將通過(guò)案例詳細(xì)講解一下動(dòng)態(tài)代理,需要的可以參考一下
    2022-02-02
  • Java中的三種校驗(yàn)注解的使用(@Valid,@Validated和@PathVariable)

    Java中的三種校驗(yàn)注解的使用(@Valid,@Validated和@PathVariable)

    本文主要介紹了Java中的三種校驗(yàn)注解的使用(@Valid,@Validated和@PathVariable),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • 詳解Spring依賴注入的三種方式以及優(yōu)缺點(diǎn)

    詳解Spring依賴注入的三種方式以及優(yōu)缺點(diǎn)

    IoC?和?DI?是?Spring?中最重要的兩個(gè)概念,其中?IoC(Inversion?of?Control)為控制反轉(zhuǎn)的思想,而?DI(Dependency?Injection)依賴注入為其(IoC)具體實(shí)現(xiàn)。那么?DI?實(shí)現(xiàn)依賴注入的方式有幾種?這些注入方式又有什么不同?本文就來(lái)和大家一起詳細(xì)聊聊
    2022-08-08
  • JPA-JpaRepository方法命名語(yǔ)法說(shuō)明

    JPA-JpaRepository方法命名語(yǔ)法說(shuō)明

    這篇文章主要介紹了JPA-JpaRepository方法命名語(yǔ)法說(shuō)明,具有很好的參考價(jià)值。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Java:com.netflix.client.ClientException錯(cuò)誤解決

    Java:com.netflix.client.ClientException錯(cuò)誤解決

    本文主要介紹了Java:com.netflix.client.ClientException錯(cuò)誤解決,主要是指出客戶端?module-sso?試圖通過(guò)負(fù)載均衡器訪問(wèn)服務(wù)時(shí),負(fù)載均衡器沒(méi)有找到可用的服務(wù)器來(lái)處理請(qǐng)求,下面就來(lái)介紹一下解決方法
    2024-08-08
  • springboot使用攔截器判斷是否登錄

    springboot使用攔截器判斷是否登錄

    這篇文章主要介紹了springboot使用攔截器判斷是否登錄,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • java json字符串轉(zhuǎn)JSONObject和JSONArray以及取值的實(shí)例

    java json字符串轉(zhuǎn)JSONObject和JSONArray以及取值的實(shí)例

    這篇文章主要介紹了java json字符串轉(zhuǎn)JSONObject和JSONArray以及取值的實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • springBoot項(xiàng)目中的全局異常處理和自定義異常處理實(shí)現(xiàn)

    springBoot項(xiàng)目中的全局異常處理和自定義異常處理實(shí)現(xiàn)

    異常是由于程序邏輯錯(cuò)誤、運(yùn)行環(huán)境問(wèn)題、用戶輸入錯(cuò)誤等原因?qū)е碌囊环N非正常的狀態(tài)或事件,本文主要介紹了springBoot項(xiàng)目中的全局異常處理和自定義異常處理實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-08-08
  • SpringCloud中的Eureka集群配置方法

    SpringCloud中的Eureka集群配置方法

    這篇文章主要介紹了SpringCloud中的Eureka集群配置,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-09-09
  • 關(guān)于Java中修飾符的總結(jié)(fina除外)

    關(guān)于Java中修飾符的總結(jié)(fina除外)

    下面小編就為大家?guī)?lái)一篇關(guān)于Java中修飾符的總結(jié)(fina除外)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-09-09

最新評(píng)論

长治县| 清丰县| 扎兰屯市| 横山县| 威宁| 新巴尔虎左旗| 区。| 怀仁县| 庆阳市| 丁青县| 拉孜县| 高碑店市| 江山市| 南平市| 抚顺市| 绩溪县| 彭泽县| 临汾市| 赤峰市| 花莲市| 仁怀市| 自治县| 泰安市| 西乌珠穆沁旗| 正定县| 惠水县| 高密市| 徐水县| 古交市| 阿拉善左旗| 抚远县| 荔浦县| 孝义市| 绥化市| 星子县| 夏河县| 扬中市| 西宁市| 麻江县| 文安县| 泗洪县|