JWorld@TW the best professional Java site in Taiwan
      註冊 | 登入 | 全文檢索 | 排行榜  

» JWorld@TW » Java 新手區 » String  

按列印兼容模式列印這個話題 列印話題    把這個話題寄給朋友 寄給朋友    訂閱主題
reply to topicthreaded modego to previous topicgo to next topic
本主題所含的標籤
無標籤
作者 [新手必看]如何有效率地使用字串 [精華]
piggy

piggy



發文: 333
積分: 2
於 2003-09-21 00:18 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
原文刊登在 2002/09/26 Java 週報上

看完上篇(請參考九月十二日的Java週報)筆者所講解的物件的比較之後,
既然講到了字串,筆者就再來跟大家討論一下,如何有效率地使用字串。
你也許會有疑問說,字串就這樣用啊,什麼叫有效率的使用字串呢?我們
先來確定一件事情,Java API說明文件上有這麼一行字:“Strings are
constant; their values cannot be changed after they are created.
String buffers support mutable strings. Because String objects
are immutable they can be shared.”。意思是字串是個常數,是不可
更改的,也就是說你對一個字串物件做任何的修改,像是加上另一個串、
把字母變大寫等等,都會產生一個新的字串物件。我們做個小小的測試,
來証明這件事情。
String str1 = new String(“hello”);
String str2 = str2;
boolean b1 = str1 == str2;

還記得上週筆者講解的字串之間比較嗎?b1得到的結果是true,代表str1
和str2參考到同一個字串物件,忘記或是不清楚的讀者,再回去翻翻週報
的內容。如果現在我們把str2加上“java”這個字串:
str2 = str2 + “java”;
boolean b2 = str1 == str2;

你會發現b2的結果是false,代表str1和str2所參考的字串物件已經不是同
一個了!現在在系統中就有三個字串物件,一個是“hello”,第二個是“
java”,第三個是“hellojava”。因為在Java中,字串有這樣一個不可修
改的特性,所以才會引發出如何有效地使用字串這個問題出來。

字串是每個應用程式都會用到的物件,常常有些程式中會對字串做大量的
運算,尤其是兩個字串的相加,例如我們寫了一個從網路上讀取網頁資料
的程式,跑個迴圈,用BufferedReader物件一次讀一行進來,然後把每一
行再加在一起。像這種很直覺、很簡單的程式,兩行就搞定了,可是JVM中
所做的事情可多了。 假設我們寫個一程式,要把一個字串一直加上“a”
一百次,很直覺得我們會這樣寫:
String str = “”;
for (int i=0; i<100; i++)
str += “a”;

可是你知道在記憶體中會產生多少的垃圾出來嗎?總共會有a、aa、aaa、
aaa….,無疑的,上述的程式雖然簡單,但浪費了不少的記憶體,而且產
生物件和物件的存取也會花掉不少的時間,我們加上幾行程式碼來測試所
花的時間和記憶體:
long startTime = System.currentTimeMillis();
long startMem = Runtime.getRuntime().freeMemory();

for (int i=0; i<1000; i++)
str += "a";

long endMem = Runtime.getRuntime().freeMemory();
System.out.println("Use memory: "+ (startMem - endMem));
long endTime = System.currentTimeMillis();
System.out.println("Use Time: "+ (endTime – startTime));

上面的程式在筆者的PIII-800的電腦上跑,平均花了50 ms和151256 bytes
的記憶體,時間還好,但記憶體使用量算蠻大的了。那我們要如何來改進
讓程式更有效率呢?因為String物件是不可修改的,可是程式中又常需要
這樣的一個動作,所以Java提供了另外一個類別,專門來處理字串運算用
的,這個類別就叫作StringBuffer。StringBuffer類別提供了很多方法來
做字串的運算,但如附加、刪除、插入、反轉、替換等等…。我們就用
StringBuffer類別所提供的附加(append)方法來做到跟上面那個例子同樣
的結果:
StringBuffer sb = new StringBuffer();
long startTime = System.currentTimeMillis();
long startMem = Runtime.getRuntime().freeMemory();

for (int i=0; i<1000; i++)
sb.append(“a”);

long endMem = Runtime.getRuntime().freeMemory();
System.out.println("Use memory: "+ (startMem - endMem));
long endTime = System.currentTimeMillis();

修改過的程式在筆者電腦上跑,平均花了0 ms和4854 bytes的記憶體。
0 ms?!多跑幾次有時會到10 ms,要看你電腦CPU目前的負載如何,不
過跟前面的例子比較起來,已經算是快了,而且記憶體也使用的非常少
。這只是個小小的例子,如果字串量再大一點,兩者的差異會更明顯。

所以結論就是,如果你的程式中會對字串做大量的修改時,請改用
StringBuffer類別,它會明顯示改進你程式的效率。至於StringBuffer
類別所提供的方法詳細的使用說明,就請自行參閱Java API。


reply to postreply to post
An Apple a day, keeps M$ away
作者 Re:[新手必看]如何有效率地使用字串 [Re:piggy]
karry





發文: 244
積分: 2
於 2004-06-12 13:22 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
對不起, 問個不知道算不算問題的問題
為何 java 在設計時要將 String 設計成不可修改
然後再去設計一個 StringBuffer 來處理這個問題
為何不直接讓 String 有 StringBuffer 的功能呢
這樣做到底有什麼好處


reply to postreply to post
作者 Re:[新手必看]如何有效率地使用字串 [Re:karry]
Biologic

生物學下的產物



發文: 524
積分: 4
於 2004-06-12 13:41 user profilesend a private message to usersend email to Biologicreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
karry wrote:
對不起, 問個不知道算不算問題的問題
為何 java 在設計時要將 String 設計成不可修改
然後再去設計一個 StringBuffer 來處理這個問題
為何不直接讓 String 有 StringBuffer 的功能呢
這樣做到底有什麼好處


個人見解是...
String 是在系統中最常被使用來交換資料的物件之一. 但不同於一般真正 primary type, 他在在傳遞的時候, 他們都是實體複製一份給另一個user. 這些資料的傳遞在系統上來說非常的快. 但是不同於 String, 他是由 charater array 組成. 如果你要傳遞 string (as parameter) 且不想擔心在 multi-thread 環境下發生 concurrency 的問題, 那其中之一的解決方案是把你的資料設計成不可變更. 這樣除了可以解決 concurrency 的問題外, 你又可以以最快速的方法讓多方同時使用資料. (這樣你就不用擔心 concurrent write/read, 還有 ooxx 的問題. 然後還要設計一大堆的 lock/unlock 的機制. 這些機制都非常浩時間)


reply to postreply to post
作者 Re:[新手必看]如何有效率地使用字串 [Re:Biologic]
karry





發文: 244
積分: 2
於 2004-06-13 15:20 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
原來如此
謝謝您的指導


reply to postreply to post
作者 Re:[新手必看]如何有效率地使用字串 [Re:piggy]
lmh0533





發文: 3
積分: 0
於 2004-07-30 14:44 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
字串量大的時候真的差狠多咧…
謝謝大大指導…^^…獲益良多…


reply to postreply to post
作者 Re:[新手必看]如何有效率地使用字串 [Re:piggy]
hkdennis2k





發文: 1926
積分: 6
於 2004-11-08 12:48 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
JDK 5.0 加入了 StringBuilder
和 StringBuffer 主要不同的時, 它不是 synconized 的, 省回了一點 overhead

javac -target 1.4
String b=a+"a";
會被 compile 為
String b=new StringBuffer(a).append("a").toString();

javac -target 1.5
String b=a+"a";
會被 compile 為
String b=new StringBuilder(a).append("a").toString();

因為 1.4 沒有 StringBuilder, 所以 javac -target 1.5 是不可以在 jvm 1.4 上運行的

另外....

static final int x=10000;

StringBuffer sb = new StringBuffer();
for (int i=0; i<x; i++)
sb.append(“a”);

StringBuffer sb = new StringBuffer(x);
for (int i=0; i<x; i++)
sb.append(“a”);

也是相差很遠的...
好像大約 20%

想想 String b=new StringBuilder(a).append("a").toString(); 吧
在大型的 loop 中, 這是突破 preformenace 的一個關口....


reply to postreply to post
作者 Re:[新手必看]如何有效率地使用字串 [Re:hkdennis2k]
Duncan

還隱隱作痛

版主

發文: 7816
積分: 39
於 2004-11-12 02:45 user profilesend a private message to usersend email to Duncanreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
hkdennis2k wrote:

另外....
1
2
3
4
5
6
7
8
9
static final int x=10000;
 
StringBuffer sb = new StringBuffer();
for (int i=0; i<x; i++)
sb.append("a"); 
 
StringBuffer sb = new StringBuffer(x);
for (int i=0; i<x; i++)
sb.append("a"); 

也是相差很遠的...
好像大約 20%


請問一下上述兩者是哪裡相差很遠?可以差到 20%?


reply to postreply to post

給我
辣味豆腐 其餘免談
作者 Re:[新手必看]如何有效率地使用字串 [Re:piggy]
hkdennis2k





發文: 1926
積分: 6
於 2004-11-14 13:10 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
StringBuilder 內部是用 char[] 實作, 而 default 只是用 char[16],
似類似 ArrayList, 當 char[] 長度不足就會用 System.arraycopy 移到另一個新的使用

1
2
3
StringBuffer sb = new StringBuffer();
for (int i=0; i<x; i++)
sb.append("a"); 

而這段 code, 會出現大當 arraycopy, new char[] 等等浪費時間的動作
連 GC 做的份也少省了下來

1
StringBuffer sb = new StringBuffer(x);

而這個, 一開始就準備了一個剛好足夠大小的 char[]

也就是, 和 ArrayList, HashMap 之類的, 利用 init 一個比較大/剛好的 array 來減少 rehash / overhead的原理一樣, 不過 StringBuffer 沒法字去更改 resize factor 就是了....

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    void expandCapacity(int minimumCapacity) {
  int newCapacity = (value.length + 1) * 2;
        if (newCapacity < 0) {
            newCapacity = Integer.MAX_VALUE;
        } else if (minimumCapacity > newCapacity) {
      newCapacity = minimumCapacity;
  }  
  char newValue[] = new char[newCapacity];
  System.arraycopy(value, 0, newValue, 0, count);
  value = newValue;
    }
    public StringBuffer append(String str) {
  if (str == null) str = "null";
        int len = str.length();
  if (len == 0) return this;
  int newCount = count + len;
  if (newCount > value.length)
      expandCapacity(newCount);
  str.getChars(0, len, value, count);
  count = newCount;
  return this;
    }


reply to postreply to post
作者 Re:[新手必看]如何有效率地使用字串 [Re:piggy]
mover





發文: 22
積分: 0
於 2004-11-27 14:04 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
现在我有一个问题了,如果我要求的不是累加字符串,而是要将字符串中的某个字符从字符串中删除。这样该如何达到目的?
是将String中的每一个字符提取到一个新的数组中,然后再把数组转化成字符串?
能不能对此作一下说明呢?谢谢。Cool


reply to postreply to post
作者 Re:[新手必看]如何有效率地使用字串 [Re:mover]
tekwei

系統穩定



發文: 978
積分: 4
於 2004-11-27 14:33 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
mover wrote:
现在我有一个问题了,如果我要求的不是累加字符串,而是要将字符串中的某个字符从字符串中删除。这样该如何达到目的?
是将String中的每一个字符提取到一个新的数组中,然后再把数组转化成字符串?
能不能对此作一下说明呢?谢谢。Cool

see substring, replaceAll........ from
http://java.sun.com/j2se/1.5.0/docs/api/java/lang/String.html


reply to postreply to post
作者 Re:[新手必看]如何有效率地使用字串 [Re:piggy]
mover





發文: 22
積分: 0
於 2004-11-27 17:05 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
好的,我去看看。谢谢。

reply to postreply to post
作者 Re:[新手必看]如何有效率地使用字串 [Re:piggy]
mover





發文: 22
積分: 0
於 2004-11-27 17:21 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
全英文的,英文学的不好哦。这下要累死了。呵呵。

reply to postreply to post
作者 Re:[新手必看]如何有效率地使用字串 [Re:piggy]
meson

東 霖 大 a ...



發文: 62
積分: 0
於 2004-12-01 22:45 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
String 是一種immutable 的類別
一被new起來後值就不能再更改的怪異類別
只能重新指向一個不同值的實体
所以用for loop去跑
1
2
3
String str = “”; 
for (int i=0; i<100; i++) 
str += “a”; 


實際上是new了 100個string 物件出來,
的確是很waste memory 的作法
用string buffer這種 mutable 的類別
當然會是較省時省空間的作法 !!
投一票讚成票 !!


reply to postreply to post
 青 春 是 一 場 棒 球 比 賽
三 人 出 局 還 會 不 會 有 延 長 加 賽 ??
作者 Re:[新手必看]如何有效率地使用字串 [Re:piggy]
老陳





發文: 161
積分: 2
於 2005-01-19 12:40 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
另外再提供一個技巧,就是比對空字串的時候,一般人會這樣比
1
a.equals("")


但如果改用下列的方式效率會更好
1
a.length() == 0


雖然""是直接去String pool裡面拿的,不用再去create一個新的String Object,但是Object的比對總是要比原生型態的效率差一點

以上提供給大家參考. 歡迎大大指較Big Smile


reply to postreply to post
電腦是害人的工具,但是上帝卻可以藉著它行奇妙的大能
作者 Re:[新手必看]如何有效率地使用字串 [Re:piggy]
fallacyjava





發文: 1
積分: 0
於 2005-03-19 22:35 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
It's kind of hard for me to read java explnanations in Chinese.
However, reading this article is really helpful.
Now I know much about the string.


reply to postreply to post
作者 Re:[新手必看]如何有效率地使用字串 [Re:piggy]
eliot





發文: 8
積分: 0
於 2005-04-09 13:07 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
It's kind of hard for me to read java explnanations in Chinese.
However, reading this article is really helpful.
Now I know much about the string.
====================
相反的狀況會更糟 Smile


reply to postreply to post
作者 Re:[新手必看]如何有效率地使用字串 [Re:piggy]
truebit





發文: 5
積分: 0
於 2005-05-15 14:56 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
谢谢各位大虾了
学了不少东西


reply to postreply to post
作者 Re:[新手必看]如何有效率地使用字串 [Re:piggy]
ncku





發文: 2
積分: 0
於 2005-05-16 22:56 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
如果我想把很多不同的字串 存放在陣列中 又要如何 作呢?

reply to postreply to post
作者 Re:[新手必看]如何有效率地使用字串 [Re:piggy]
Presell





發文: 10
積分: 0
於 2005-05-31 10:21 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
更改的,也就是說你對一個字串物件做任何的修改,像是加上另一個串、
把字母變大寫等等,都會產生一個新的字串物件。我們做個小小的測試,
來証明這件事情。
String str1 = new String(“hello”);
String str2 = str2;
      ^^^^
      大大…不知道您是不是筆誤?我覺得,這裡是放str1吧?
boolean b1 = str1 == str2;

正在鑽研您的文章,辛苦了!


reply to postreply to post
作者 Re:[新手必看]如何有效率地使用字串 [Re:piggy]
earow

Anti M$



發文: 87
積分: 1
於 2005-05-31 16:13 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
好文阿...感恩
用力推


reply to postreply to post
作者 Re:[新手必看]如何有效率地使用字串 [Re:piggy]
neyney1





發文: 6
積分: 0
於 2005-06-16 18:53 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
棒!!
正想要問問為什麼在
jdk1.5.0裡面使用StringBuffer 一值append字串會有錯誤
而在jdk1.4.2不會有錯誤,這篇文章讓我解惑啦~~~


reply to postreply to post
作者 Re:[新手必看]如何有效率地使用字串 [Re:piggy]
a0937963997





發文: 2
積分: 0
於 2005-07-26 16:49 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
最近才開始使用JAVA,看了許多大大的分析!
大大們謝謝你們的指導!


reply to postreply to post
作者 Re:[新手必看]如何有效率地使用字串 [Re:neyney1]
阿刃

生活就像 RPG



發文: 121
積分: 3
於 2005-07-26 20:26 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
neyney1 wrote:
棒!!
正想要問問為什麼在
jdk1.5.0裡面使用StringBuffer 一值append字串會有錯誤
而在jdk1.4.2不會有錯誤,這篇文章讓我解惑啦~~~


恕小弟無能...看完整個討論串...
小弟沒看出"jdk1.5.0裡面使用StringBuffer 一值append字串會有錯誤..而在jdk1.4.2不會有錯誤"的原因

還請大大指點


reply to postreply to post
A never ending story with Java...

My blog => 【刃™】ThiS WORLD, MY WORLD
作者 Re:[新手必看]如何有效率地使用字串 [Re:阿刃]
阿刃

生活就像 RPG



發文: 121
積分: 3
於 2005-07-26 20:28 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
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
        int x = 10000;        
        long start;
        start = System.nanoTime();
        StringBuffer sb = new StringBuffer();
        for (int i=0; i<x; i++)
            sb.append("a");
        System.out.println(System.nanoTime()-start);
        
        start = System.nanoTime();
        StringBuffer sb2 = new StringBuffer( x);
        for (int i=0; i<x; i++)
            sb2.append("a");
        System.out.println(System.nanoTime()-start);
        
        start = System.nanoTime();
        StringBuilder SB = new StringBuilder();
        for (int i=0; i<x; i++)
            SB.append("a");
        System.out.println(System.nanoTime()-start);
        
        start = System.nanoTime();
        StringBuilder SB2 = new StringBuilder( x);
        for (int i=0; i<x; i++)
            SB2.append("a");
        System.out.println(System.nanoTime()-start);

實驗結果為
9585017
4776584
2890590
1186743
速度還相差真懸殊@@..小弟受教了~


阿刃 edited on 2005-07-26 20:35
reply to postreply to post
A never ending story with Java...

My blog => 【刃™】ThiS WORLD, MY WORLD
作者 Re:[新手必看]如何有效率地使用字串 [Re:阿刃]
neyney1





發文: 6
積分: 0
於 2005-10-12 16:16 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
阿刃 wrote:
恕小弟無能...看完整個討論串...
小弟沒看出"jdk1.5.0裡面使用StringBuffer 一值append字串會有錯誤..而在jdk1.4.2不會有錯誤"的原因

還請大大指點

痾....關於這一點
我有點不好意思....
我開發工具是用WSAD.....
有一次我把專案的預設java執行環境改成1.5.0_04
他會把我寫的
1
2
3
4
5
6
StringBuffer sb = new StringBuffer();
sb.append("xxx").append("oooo"); // <==這裡會顯示編譯錯誤的訊息
//說 類型 AbstractStringBuilder 不可見
//但是程式這樣寫就可以
sb.append("xxx");
sb.append("ooo");

所以...我就把執行java環境改回來14.2_04囉


reply to postreply to post
go to first page go to previous page  1   2  go to next page go to last page
» JWorld@TW »  Java 新手區 » String

reply to topicthreaded modego to previous topicgo to next topic
  已讀文章
  新的文章
  被刪除的文章
Jump to the top of page

JWorld@TW 本站商標資訊

Powered by Powerful JuteForum® Version Jute 1.5.8