String和StringBuilder和StringBuffer三兄弟
String和StringBuilder和StringBuffer三兄弟
前言
好久之前在寫檔案上傳的時候使用了這樣的一段程式碼
/**
* @param rootUrlStr:儲存的路徑的資料夾路徑 假設就是 D:\save
* @param fileUriStr:需要儲存的檔案的具體路徑
* @about 這是一段精簡的程式碼
* @return 儲存檔案地址
*/
public String uploadUri1(String rootUrlStr,String fileUriStr) {
//下面我將故意使用很複雜的拼接
//獲得檔名,故意不使用UUID.randomUUID()
String fileNameStr=fileUriStr.substring(fileUriStr.lastIndexOf("\\"));
String fileRealUriStr=rootUrlStr+"\\";
fileRealUriStr+="uploadFile\\";
fileRealUriStr+=fileNameStr;//把根路徑和檔名拼接在一起
return fileRealUriStr;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
這種寫法很明顯的一點就是會生成很多的中間物件。
於是我後來改成了這樣
public String uploadUri2(String rootUrlStr,String fileUriStr) {
//下面我將故意使用很複雜的拼接
//獲得檔名,故意不使用UUID.randomUUID()
StringBuffer fileRealUriStr=new StringBuffer(rootUrlStr);
String fileNameStr=fileUriStr.substring(fileUriStr.lastIndexOf("\\"));
fileRealUriStr.append("uploadFile\\").append(fileNameStr);
return fileRealUriStr.toString();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
使用StringBuffer去避免生成太多臨時字串。
當然有更好的方法,那就是使用Paths
public String uploadUri3(String rootUrlStr,String fileUriStr) {
//下面使用Path
//獲得檔名,故意不使用UUID.randomUUID()
String fileNameStr=fileUriStr.substring(fileUriStr.lastIndexOf("\\"));
Path path=Paths.get(rootUrlStr,"uploadFile",fileNameStr);
return path.toString();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
Paths會自動補全”\”,使得程式碼比較直觀好看。他不是今天的主角,所以我就不展開講了。
//測試程式碼
public static void main(String[] args) {
String string1=new MyText().uploadUri1("D:save","I:\\JAVA\\java.txt");
String string2=new MyText().uploadUri2("D:save","I:\\JAVA\\java.txt");
String string3=new MyText().uploadUri3("D:save","I:\\JAVA\\java.txt");
System.out.println(string1);
System.out.println(string2);
System.out.println(string3);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
輸出結果
D:save\uploadFile\Java.txt
D:save\uploadFile\java.txt
D:save\uploadFile\java.txt
以上是可以跳過不看的內容
分析
內部實現
-
String:
String類使用字串陣列儲存字串,因為使用final修飾符,所以可知道String物件是不可變的。所謂的不可變其實是指每次修改都不是在原字元上修改,而是新建了一個新的字元陣列,而且如果這個物件沒有被引用,那這個物件就是沒有用的。
-
StringBuffer:
繼承了AbstractStringBuilder,而且和String不一樣的是
String使用的是陣列宣告為 private final char value[];
StringBuffer的宣告是 private transient char[] toStringCache;
transient :臨時的
當StringBuffer進行修改時,(比如說刪除、更新字元)是在原來的例項物件進行修改的。但是如果是拼接操作時,分成兩種情況,1、空間足夠,直接拼接;2、空間不夠,新建了一個字串陣列,再搬家過去。 -
StringBuilder:
StringBuffer和StringBuffer都是繼承了AbstractStringBuilder,區別只是方法簽名上是否有synchronized。因此,StringBuffer是執行緒安全的,而StringBuilder是執行緒不安全的。
HashTable是執行緒安全的,很多方法都是synchronized方法,而HashMap不是執行緒安全的,但其在單執行緒程式中的效能比HashTable要高。StringBuffer和StringBuilder類的區別也是如此,他們的原理和操作基本相同,區別在於StringBufferd支援併發操作,線性安全的,適 合多執行緒中使用。StringBuilder不支援併發操作,線性不安全的,不適合多執行緒中使用。新引入的StringBuilder類不是執行緒安全的,但其在單執行緒中的效能比StringBuffer高。
執行速度(StringBuilder>StringBuffer>String)
- String 每次都要新增臨時字串,開銷大,很慢(GC工作壓力大)
- StringBuffer 建立執行緒安全容器,開銷大,中等
- StringBuilder 單執行緒推薦使用,執行緒不安全,快
感覺直接這樣說,你還是不相信,還是覺得使用String多好啊,敲起來還短,所以我就提供了一段程式碼,這段程式碼不是我原創的,但是寫的很好,我就借來修改了一下,程式碼如下
package javaTest;
/**
*@author CHEN
*@time 2016年4月15日
*@about 測試String StringBuffer StringBuilder的效能
*/
public class StringBuilderTester {
private static final String base = " base string. ";
private static final int count = 200000;
public static void stringTest() {
long begin, end;
begin = System.currentTimeMillis();
String test = new String(base);
for (int i = 0; i < count ; i++) {
test = test + " add ";
}
end = System.currentTimeMillis();
System.out.println((end - begin)
+ " millis has elapsed when used String. ");
}
public static void stringBufferTest() {
long begin, end;
begin = System.currentTimeMillis();
StringBuffer test = new StringBuffer(base);
for (int i = 0; i < count; i++) {
test = test.append(" add ");
}
end = System.currentTimeMillis();
System.out.println((end - begin)
+ " millis has elapsed when used StringBuffer. ");
}
public static void stringBuilderTest() {
long begin, end;
begin = System.currentTimeMillis();
StringBuilder test = new StringBuilder(base);
for (int i = 0; i < count; i++) {
test = test.append(" add ");
}
end = System.currentTimeMillis();
System.out.println((end - begin)
+ " millis has elapsed when used StringBuilder. ");
}
public static void main(String[] args) {
stringTest();
stringBufferTest();
stringBuilderTest();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
執行結果:
113730 millis has elapsed when used String.
13 millis has elapsed when used StringBuffer.
9 millis has elapsed when used StringBuilder.
建議在使用的時候,把count的值乘以10,但stringTest中count縮小100倍,有利於比較StringBuffer和StringBuilder。
執行緒安全
- String :String是不可變的,所以也就是執行緒安全的
- StringBuffer:執行緒安全,
- StringBuilder:執行緒不安全
package hello;
/**
* @about 對StringBuffer StringBuilder String的執行緒測試
* @author CHEN
* @time 2016年4月15日
*/
public class Test {
public static void main(String[] args) {
StringBuffer sbf = new StringBuffer();
StringBuilder sb = new StringBuilder();
String s=new String();
//10個執行緒
for (int i = 0; i < 10; i++) {
new Thread(new TestThread(sbf, sb, s)).start();
}
}
}
class TestThread implements Runnable {
StringBuffer sbf;
StringBuilder sb;
String s;
TestThread(StringBuffer sbf, StringBuilder sb,String s) {
this.sb = sb;
this.sbf = sbf;
this.s=s;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
sb.append("1");
sbf.append("1");
s+="1";
System.out.println(sb.length() + "/" + sbf.length()+"/"+s.length());
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
執行的結果是:
sb很少次能達到1000次
sbf基本都達到1000次
而s 則是100次
後言
- 如果閱讀String的“+”的位元組碼,其實你就會發現,在底層,系統自動呼叫了StringBilder。
例如下面的程式碼
public class Buffer {
public static void main(String[] args) {
String s1 = "aaaaa";
String s2 = "bbbbb";
String r = null;
int i = 3694;
r = s1 + i + s2;
for(int j=0;i<10;j++){
r+="23124";
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
JVM將會翻譯成
偷偷的呼叫了StringBuilder,為什麼呢?當然是因為快啊。但是別以為JVM幫你做了這部分工作,你就可以濫用String了。String轉成StringBuilder每次都會建立很多的物件的,所以呢,作為一個好的碼農,第一件事就是為JVM多考慮。
總結
就這樣我們認識了String、StringBuffer、StringBuilder三兄弟。
大哥String,雖說頑固不變,但是通用性好,用途廣泛,佔用記憶體小,大眾都喜歡使用它。可是呢,其實大哥String的工作經常是交給小弟StringBuilder做的。
二哥StringBuffer,比大哥通達,改變的時候就會改變。可是,別人讓他辦事,他每次就答應辦一件,每次一件,所以比較可靠安全。
小弟StringBuilder,比較活潑,有時候同時辦好幾件事,就把事給辦壞了。可是呢,小弟他的工作效率是最快的。
相關文章
- String、StringBuilder和StringBufferUI
- 【Java】String、StringBuilder和StringBufferJavaUI
- java String,StringBuilder和StringBufferJavaUI
- [Java]String、StringBuilder和StringBufferJavaUI
- String、StringBuffer和StringBuilder類的UI
- C# string、stringBuffer和stringBuilderC#UI
- StringBuilder、StringBuffer和String三者的聯絡和區別(轉)UI
- Java String StringBuilder 和 StringBuffer 用法詳解JavaUI
- Java 之String、StringBuffer 和 StringBuilder 三者區別介紹JavaUI
- 從為什麼String=String談到StringBuilder和StringBufferUI
- StringBuffer和StringBuilderUI
- String、StringBuffer、StringBuilder剖析UI
- StringBuffer 和 StringBuilder 類UI
- Java中String,StringBuffer和StringBuilder的區別(轉載)JavaUI
- String StringBuffer StringBuilder 三者的區別UI
- String、StringBuffer、StringBuilder區別?UI
- String、StringBuffer、StringBuilder的理解UI
- String,StringBuffer,StringBuilder區別UI
- 第二十節:詳細講解String和StringBuffer和StringBuilder的使用UI
- Java StringBuffer 和 StringBuilder 類JavaUI
- stringbuilder和stringbuffer區別UI
- 面試常備,字串三劍客 String、StringBuffer、StringBuilder面試字串UI
- 老生常談 String、StringBuilder、StringBufferUI
- String,StringBuilder,StringBuffer的區別UI
- String、StringBuilder、StringBuffer的區別UI
- Java字串(String_StringBuilder_StringBuffer)Java字串UI
- 正確使用String,StringBuffer,StringBuilderUI
- String、StringBuffer、StringBuilder的區別UI
- java中String、StringBuilder、StringBuffer三者的區別JavaUI
- StringBuffer和StringBuilder的區別UI
- StringBuilder和StringBuffer的區別UI
- Java中的String,StringBuilder,StringBuffer三者的區別JavaUI
- String,StringBuffer與StringBuilder的區別UI
- java複習之 String,StringBuffer,StringBuilderJavaUI
- String、StringBuffer、與StringBuilder的區別UI
- String,StringBuffer與StringBuilder的區別??UI
- Java StringBuilder和StringBuffer原始碼分析JavaUI原始碼
- System,Runtime,Math,StringBuffer和StringBuilderUI