Vincent.Chan‘s Blog

          常用鏈接

          統計

          積分與排名

          網站

          最新評論

          如何有效率地使用字串

          原文刊登在 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 = newString(“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 = newStringBuffer();
          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。



          作者: hkdennis2k

          JDK 5.0 加入了 StringBuilder
          和 StringBuffer 主要不同的時, 它不是 synconized 的, 省回了一點 overhead

          javac -target 1.4
          String b=a+"a";

          會被 compile 為

          								String b=newStringBuffer(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 = newStringBuffer();
          for (int i=0; i<x; i++)
          sb.append(“a”);

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

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

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



          作者: hkdennis2k

          StringBuilder 內部是用 char[] 實作, 而 default 只是用 char[16],
          似類似 ArrayList, 當 char[] 長度不足就會用 System.arraycopy 移到另一個新的使用

          								StringBuffer sb = newStringBuffer();
          for (int i=0; i<x; i++)
          sb.append("a");

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

          								StringBuffer sb = newStringBuffer(x);

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

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

          void expandCapacity(int minimumCapacity) {
          int newCapacity = (value.length + 1) * 2;
          if (newCapacity < 0) {
          newCapacity = Integer.MAX_VALUE;
          } elseif (minimumCapacity > newCapacity) {
          newCapacity = minimumCapacity;
          }
          char newValue[] = newchar[newCapacity];
          System.arraycopy(value, 0, newValue, 0, count);
          value = newValue;
          }
          publicStringBuffer append(String str) {
          if (str == null) str = "null";
          int len = str.length();
          if (len == 0) returnthis;
          int newCount = count + len;
          if (newCount > value.length)
          expandCapacity(newCount);
          str.getChars(0, len, value, count);
          count = newCount;
          returnthis;
          }



          作者: 老陳

          另外再提供一個技巧,就是比對空字串的時候,一般人會這樣比

          a.equals("")

          但如果改用下列的方式效率會更好

          a.length() == 0

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

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

          posted on 2006-03-23 00:00 Vincent.Chen 閱讀(269) 評論(0)  編輯  收藏 所屬分類: Java

          主站蜘蛛池模板: 新竹县| 通河县| 新晃| 龙游县| 五河县| 青海省| 永泰县| 平顶山市| 土默特左旗| 巴楚县| 琼海市| 宣威市| 蓬溪县| 石河子市| 综艺| 岫岩| 永和县| 沁水县| 宣恩县| 东光县| 临夏市| 香格里拉县| 昭平县| 徐汇区| 衡水市| 永兴县| 靖安县| 海原县| 高密市| 贡嘎县| 塔河县| 崇阳县| 祁连县| 靖江市| 舟曲县| 乌什县| 东乌| 孙吴县| 霍山县| 吴川市| 四会市|