解讀StringBuilder為何比String節(jié)省效率
StringBuilder為何比String節(jié)省效率
通常說(shuō)StringBuilder比String節(jié)省效率一般是指在對(duì)字符串進(jìn)行一定的操作,比如拼接、反轉(zhuǎn)等,那么究竟為什么節(jié)省效率呢,本篇將從字符串拼接的原理來(lái)講述
字符串拼接的兩種實(shí)現(xiàn)
在Java中用加號(hào)對(duì)字符串進(jìn)行拼接操作通常有兩種情況
1.沒有變量的字符串拼接
String s1 = "abc" + "123" + "xyz";
這種不涉及變量的字符串拼接是相當(dāng)簡(jiǎn)單的,在編譯階段,會(huì)觸發(fā)字符串的優(yōu)化機(jī)制,對(duì)于只是簡(jiǎn)單字符串常量之間的拼接,編譯過(guò)后的結(jié)果就是他的最終值,也就是說(shuō),上面的s1在編譯時(shí)的值就已經(jīng)是"abc123xyz"
了“
String s1 = "abc123xyz";
2.帶有變量的字符串拼接
String s1 = "abc"; String s2 = s1 + "123";
這種帶有變量的字符串拼接操作的實(shí)現(xiàn)就相對(duì)來(lái)說(shuō)比較復(fù)雜一些,他的實(shí)現(xiàn)原理在JDK8前后也不同
JDK8之前是創(chuàng)建一個(gè)StringBuilder進(jìn)行操作
當(dāng)給s1直接賦值”abc“時(shí),在內(nèi)存的字符串常量池中會(huì)生成一個(gè)”abc“,并且s1變量引用在串池中的地址,當(dāng)為s2賦值時(shí),由于拼接操作涉及到另一個(gè)變量,堆內(nèi)存中會(huì)自動(dòng)生成一個(gè)StringBuilder空對(duì)象,然后再將s1的內(nèi)容與”123“全部拼接到這個(gè)StringBuilder的對(duì)象中,串池中也會(huì)留下”123“,然后再調(diào)用這個(gè)StringBuilder對(duì)象的toString方法將其轉(zhuǎn)換為字符串并賦值給s2
大致的過(guò)程等價(jià)于:
String s2 = new StringBuilder().append(s1).append("123").toString();
那么他的實(shí)現(xiàn)都使用了StringBuilder,為什么還說(shuō)這種拼接方式效率不高呢?
假如說(shuō)我們?cè)O(shè)計(jì)了多次的字符串拼接操作:
String s1 = "abc"; String s2 = s1 + "123"; String s3 = s2 + "xyz"; String s4 = s3 + "111"; ...
每次涉及到變量的拼接操作都會(huì)在堆內(nèi)存中生成一個(gè)StringBuilder對(duì)象和一個(gè)String對(duì)象來(lái)接收拼接后的字符串,如果連續(xù)使用這種拼接方式拼接10次,那么在內(nèi)存中就需要開辟20個(gè)新的對(duì)象,顯然這種方式并不是我們想要的
在JDK8之后會(huì)使用預(yù)估字符串長(zhǎng)度的方式來(lái)完成拼接
String s1 = "a"; String s2 = "b"; String s3 = "c"; String result = s1 + s2 + s3;
在進(jìn)行字符串拼接之前,會(huì)先預(yù)估字符串拼接后的長(zhǎng)度,并為其開辟一個(gè)等長(zhǎng)的數(shù)組,再依次把數(shù)據(jù)放入數(shù)組中,最后再完成拼接操作,把數(shù)組轉(zhuǎn)換為一個(gè)字符串:
雖然說(shuō)相比起JDK8之前,這種方法確實(shí)提高了拼接效率,但是同樣的問題也出現(xiàn)了:
String s1 = "abc"; String s2 = s1 + "123"; String s3 = s2 + "xyz"; String s4 = s3 + "111";
當(dāng)設(shè)計(jì)到多次拼接時(shí),就要進(jìn)行多次預(yù)估長(zhǎng)度,并且產(chǎn)生多個(gè)數(shù)組,同樣極其浪費(fèi)空間
使用StringBuilder
使用 StringBuilder 拼接字符串比直接使用 String 更高效,主要是因?yàn)椋?/p>
- 可變性:而 StringBuilder 是可變的,它在內(nèi)部維護(hù)一個(gè)字符數(shù)組,可以在原有的基礎(chǔ)上進(jìn)行修改。
- 性能開銷:使用 String 拼接時(shí),每次都要復(fù)制原有字符串和新添加的部分,這在多次拼接時(shí)會(huì)顯著增加時(shí)間復(fù)雜度。StringBuilder 通過(guò)直接在內(nèi)部數(shù)組中修改數(shù)據(jù),避免了這些額外的復(fù)制操作。
也就是說(shuō),無(wú)論進(jìn)行多少次拼接,他的操作永遠(yuǎn)在一個(gè)StringBuilder容器內(nèi)進(jìn)行直接操作,不會(huì)額外開辟其他的空間
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Feign如何設(shè)置超時(shí)時(shí)間(不同情況)
本文主要介紹了Feign的超時(shí)時(shí)間設(shè)置,包括單獨(dú)使用Feign和在SpringCloud環(huán)境下的設(shè)置方式,以及與Ribbon和Hystrix的配合使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-11-11詳解SpringBoot優(yōu)雅編碼之Lombok加持
這篇文章主要介紹了詳解SpringBoot優(yōu)雅編碼之Lombok加持,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-06-06Java服務(wù)限流算法的6種實(shí)現(xiàn)
服務(wù)限流是指通過(guò)控制請(qǐng)求的速率或次數(shù)來(lái)達(dá)到保護(hù)服務(wù)的目的,本文主要介紹了Java服務(wù)限流算法的6種實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2023-05-05SpringBoot配置Druid數(shù)據(jù)監(jiān)控代碼實(shí)例
這篇文章主要介紹了SpringBoot配置Druid數(shù)據(jù)監(jiān)控代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06springboot如何通過(guò)@Value,@ConfigurationProperties獲取配置
這篇文章主要介紹了springboot如何通過(guò)@Value,@ConfigurationProperties獲取配置,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03IDEA2020.1個(gè)性化設(shè)置的實(shí)現(xiàn)
這篇文章主要介紹了IDEA2020.1個(gè)性化設(shè)置的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08springboot對(duì)接第三方微信授權(quán)及獲取用戶的頭像和昵稱等等
這篇文章主要介紹了springboot對(duì)接第三方微信授權(quán)及獲取用戶的頭像和昵稱等等,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01說(shuō)說(shuō)字符串轉(zhuǎn) OffSetDateTime 你真的會(huì)用嗎
這篇文章主要介紹了字符串轉(zhuǎn) OffSetDateTime 你真的會(huì)用嗎?具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08