迷失
          我真的迷失了,迷失了自己,哪里是屬于我的地方?哪里有我的愛?
          posts - 7,comments - 12,trackbacks - 0

          本文作者: 大阿福 (toafu2002@yahoo.com.cn )

          摘要:Java之所以得到很多程序員的青睞,除了她的嚴謹的面向對象特性外,還有一個不容輕視的因素,那就是她強大的類庫。一門語言如果沒有庫,功能將會大打折扣,在JDK5.0版本中,其核心庫也有了諸多的改進,本文將就其新特性進行簡介。

          1.1.        事務的屬性

          1.1.1.    訪問環境變量

          雖然Java從一開始推出的時候,就一再強調她的跨平臺特性,“一次編譯,到處運行”。所以能夠訪問平臺專有信息的System.getenv()方法從一開始進入javalang包時,就遭到了大多數人的反對。雖然1.0版本中拋棄了其中的一些內容,但是在tiger版本中我們又可以使用這個方法了,請注意該方法的名稱全部是小寫。

          使用的方法很簡單:如清單1

          public class EnvTest {

          public static void main(String args[]) {

          System.out.println(System.getenv(args[0]));

          }

          }

          只要給定變量的名稱,就可以得到它的當前值。

          Tiger提供了兩個版本的getenv(),第二個版本返回系統當前設置中所有的環境變量對應的“名值”對。清單2說明該方法的使用:

          import java.util.Map;

          public class EnvDump {

          public static void main(String args[]) {

          for (Map.Entry entry: System.getenv().entrySet()) {

          System.out.println(entry.getKey() + “/” + entry.getValue());

          }

          }

          }

          1.1.2.    訪問子進程

          J2SE平臺的前期版本提供了Runtime類的exec()方法用來創建子進程的運行,在Tiger版本中,這個方法依然有效,但是為了更方便的定制子進程,Tiger提供了ProcessBuilder類,它使依據改變了的進程變量來創建子進程更加便利。ProcessBuilder提供了directory(File)方法來改變進程的工作目錄,用enviroment()方法在進程空間中添加和刪除環境變量。清單3說明了Processor的簡單用法,它使用 ipconfig 命令獲得 Internet 配置信息。該方法適用于多數平臺,否則可以將 ipconfig 改寫成所用平臺上的工作命令。啟動進程構造程序之后,需要獲得其 InputStream,以讀入所創建進程的結果。

          import java.io.*;

          public class ProcessTest {

          public static void main(String args[]) throws IOException {

          Process p = new ProcessBuilder("ipconfig").start();

          InputStream is = p.getInputStream();

          BufferedReader br = new BufferedReader(new InputStreamReader(is));

          String line;

          while ((line = br.readLine()) != null) {

          System.out.println(line);

          }

          }

          }

          運行結果如清單4

          Windows 2000 IP Configuration

           

          Ethernet adapter 本地連接:

           

          Connection-specific DNS Suffix  . :

          IP Address. . . . . . . . . . . . : 10.97.69.166

          Subnet Mask . . . . . . . . . . . : 255.255.255.128

          Default Gateway . . . . . . . . . : 10.97.69.129

          ProcessBuilder 類不僅能生成新的進程,而且還能獲得其結果。在調用其 start() 方法之前,還可以調整進程所執行的上下文。如果不喜歡環境變量,可以使用 environment 獲得當前設置,并調用 clear() 清除映射。如果需要添加環境變量,可以調用 environment 獲得當前設置,然后通過 put(name, value) 添加新的變量。如果希望使用新的工作目錄,可以調用 directory() 并提供新的工作目錄作為 File 對象。就是這么簡單。

          使用表示將運行的命令及其參數的數目可變的字符串參數來創建 ProcessBuilder,一旦使用新的環境變量和工作目錄配置 ProcessBuilder,就可以調用 start() 來執行命令。

          1.2.        并發集合

          Java中的集合框架一直是令人津津樂道的,在Tiger中,集合框架新添加了Queue接口以及這個接口的并發和非并發實現,以及并發Map的實現和專用于讀操作大大超過寫操作的情況下的并發ListSet實現。

          1.2.1.    Queue接口

          雖然在List的兩端可以添加刪除元素達到模擬queue的性能,但是Queue的提出提供了支持添加、刪除和檢查集合的更為方便的方法:如清單5所示

          public boolean offer(Object element)

          public Object remove()

          public Object poll()

          public Object element()

          public Object peek()

          一些隊列有大小長度的限制,因此如果想在一個已滿的隊列中加入一個新項,多出的項就會被拒絕。這時新的 offer 方法就可以起作用了。它不是對調用 add() 方法拋出一個 unchecked 異常,而只是得到由 offer() 返回的 false。remove() poll() 方法都是從隊列中刪除第一個元素(head)。remove() 的行為與 Collection 接口的版本相似,但是新的 poll() 方法在用空集合調用時不是拋出異常,只是返回 null。因此新的方法更適合容易出現異常條件的情況。后兩個方法 element() peek() 用于在隊列的頭部查詢元素。與 remove() 方法類似,在隊列為空時,element() 拋出一個異常,而 peek() 返回 null。

          1.2.1.1.        基本隊列實現

          1、  Tiger中,java.util.LinkedList已經被改造為實現了java.util.Listjava.util.Queue兩個接口。清單6顯示的是LinkedList的簡單使用:

          Queue queue = new LinkedList();

          queue.offer("One");

          queue.offer("Two");

          queue.offer("Three");

          queue.offer("Four");

          System.out.println("Head of queue is: " + queue.poll());

                 輸出的結果應該是One

          2、  util包新增加的AbstractQueue類,其工作方式類似于AbstractListAbstractSet類,在需要創建自己所需的對壘時,可以直接繼承該類,必須實現offer(),poll()peek()三個方法,讀者可以在其中提供優化的實現。讀者也可以不必創建自己的子類,而是使用幾個tiger提供的實現,其中兩個時不阻塞隊列:PriorityQueueConcurrentLinkedQueuePriorityQueue類實際上是維護了一個有序的隊列,加入到該Queue中的元素按照它們的自然順序來進行排序,排序的依據是元素對java.util.Comparable的實現或者傳遞給該Queue構造函數的Comparator參數。如果將清單6的具體實現改為PriorityQueue,則輸入的結果應該為Four,因為按字母順序排列,Four是排在了第一個。ConcurrentLinkedQueue 是基于鏈接節點的、線程安全的隊列。并發訪問不需要同步。因為它在隊列的尾部添加元素并從頭部刪除它們,所以不需要知道隊列的大小,ConcurrentLinkedQueue 對公共集合的共享訪問就可以工作得很好。收集關于隊列大小的信息會很慢,需要遍歷隊列。

          1.2.1.2.        阻塞隊列實現

          Tiger提供的 java.util.concurrent 包在 集合框架 中加入了 BlockingQueue 接口和五個阻塞隊列類。簡單的講,阻塞隊列的意思就是當隊列無空間時,添加元素的線程執行操作阻塞,直到有空間;或者是,當隊列為空無元素可刪時,執行刪除的線程阻塞,知道有元素可刪。BlockingQueue 接口的 Javadoc 給出了阻塞隊列的基本用法,如清單 7 所示。生產者中的 put() 操作會在沒有空間可用時阻塞,而消費者的 take() 操作會在隊列中沒有任何東西時阻塞。

          class Producer implements Runnable {

             private final BlockingQueue queue;

             Producer(BlockingQueue q) { queue = q; }

             public void run() {

               try {

                 while(true) { queue.put(produce()); }

               } catch (InterruptedException ex) { ... handle ...}

             }

             Object produce() { ... }

           }

           

           class Consumer implements Runnable {

             private final BlockingQueue queue;

             Consumer(BlockingQueue q) { queue = q; }

             public void run() {

               try {

                 while(true) { consume(queue.take()); }

               } catch (InterruptedException ex) { ... handle ...}

             }

             void consume(Object x) { ... }

           }

           

           class Setup {

             void main() {

               BlockingQueue q = new SomeQueueImplementation();

               Producer p = new Producer(q);

               Consumer c1 = new Consumer(q);

               Consumer c2 = new Consumer(q);

               new Thread(p).start();

               new Thread(c1).start();

               new Thread(c2).start();

             }

           }

          另外五個阻塞隊列提供的情況各有不同:

          • ArrayBlockingQueue:一個由數組支持的有界隊列。
          • LinkedBlockingQueue:一個由鏈接節點支持的可選有界隊列。
          • PriorityBlockingQueue:一個由優先級堆支持的無界優先級隊列。
          • DelayQueue:一個由優先級堆支持的、基于時間的調度隊列。
          • SynchronousQueue:一個利用 BlockingQueue 接口的簡單聚集(rendezvous)機制

           

          前兩個類 ArrayBlockingQueue LinkedBlockingQueue 幾乎相同,只是在底層存儲實現方面有所不同,LinkedBlockingQueue 并不總是有容量界限。無大小界限的 LinkedBlockingQueue 類在添加元素時永遠不會有阻塞隊列的等待(至少在其中有 Integer.MAX_VALUE 元素之前不會,這個時候采用的容量限制即是Integer.MAX_VALUE)。

           

          PriorityBlockingQueue 是具有無界限容量的隊列,它利用所包含元素的 Comparable 排序順序來以邏輯順序維護元素。可以將它看作 TreeSet 的可能替代物。例如,在隊列中加入字符串 One、Two、Three Four 會導致 Four 被第一個取出來。對于沒有天然順序的元素,可以為構造函數提供一個 Comparator 。不過對 PriorityBlockingQueue使用時需要注意,從 iterator() 返回的 Iterator 實例并不一定按照優先級順序返回元素。如果必須以優先級順序遍歷所有元素,那么讓它們都通過 toArray() 方法并自己對它們排序,像 Arrays.sort(pq.toArray())。

          新的 DelayQueue 實現可能是其中最有意思(也是最復雜)的一個。加入到隊列中的元素必須實現新的 Delayed 接口(只有一個方法 —— long getDelay(java.util.concurrent.TimeUnit unit))。因為隊列的大小沒有界限,使得添加可以立即返回,但是在延遲時間過去之前,不能從隊列中取出元素。如果多個元素完成了延遲,那么最早失效/失效時間最長的元素將第一個取出。實際上沒有聽上去這樣復雜。清單8演示了這種新的阻塞隊列集合的使用:

           

          import java.util.*;

          import java.util.concurrent.*;

           

          public class Delay {

            /**

             * Delayed implementation that actually delays

             */

            static class NanoDelay implements Delayed {

              long trigger;

              NanoDelay(long i) {

                trigger = System.nanoTime() + i;

              }

              public int compareTo(Object y) {

                long i = trigger;

                long j = ((NanoDelay)y).trigger;

                if (i < j) return -1;

                if (i > j) return 1;

                return 0;

              }

              public boolean equals(Object other) {

                return ((NanoDelay)other).trigger == trigger;

              }

              public boolean equals(NanoDelay other) {

                return other.trigger == trigger;

              }

              public long getDelay(TimeUnit unit) {

                long n = trigger - System.nanoTime();

                return unit.convert(n, TimeUnit.NANOSECONDS);

              }

              public long getTriggerTime() {

                return trigger;

              }

              public String toString() {

                return String.valueOf(trigger);

              }

            }

            public static void main(String args[]) throws InterruptedException {

              Random random = new Random();

              DelayQueue queue = new DelayQueue();

              for (int i=0; i < 5; i++) {

                queue.add(new NanoDelay(random.nextInt(1000)));

              }

              long last = 0;

              for (int i=0; i < 5; i++) {

                NanoDelay delay = (NanoDelay)(queue.take());

                long tt = delay.getTriggerTime();

                System.out.println("Trigger time: " + tt);

                if (i != 0) {

                  System.out.println("Delta: " + (tt - last));

                }

                last = tt;

              }

            }

          }

           

          這個例子首先是一個內部類 NanoDelay,它實質上將暫停給定的任意納秒(nanosecond)數,這里利用了 System 的新 nanoTime() 方法。然后 main() 方法只是將 NanoDelay 對象放到隊列中并再次將它們取出來。如果希望隊列項做一些其他事情,就需要在 Delayed 對象的實現中加入方法,并在從隊列中取出后調用這個新方法。(請隨意擴展 NanoDelay 以試驗加入其他方法做一些有趣的事情。)顯示從隊列中取出元素的兩次調用之間的時間差。如果時間差是負數,可以視為一個錯誤,因為永遠不會在延遲時間結束后,在一個更早的觸發時間從隊列中取得項。

          SynchronousQueue 類是最簡單的。它沒有內部容量。它就像線程之間的手遞手機制。在隊列中加入一個元素的生產者會等待另一個線程的消費者。當這個消費者出現時,這個元素就直接在消費者和生產者之間傳遞,永遠不會加入到阻塞隊列中

           

          1.2.2.    ConcurrentMap實現

          新的 java.util.concurrent.ConcurrentMap 接口和 ConcurrentHashMap 實現只能在鍵不存在時將元素加入到 map 中,只有在鍵存在并映射到特定值時才能從 map 中刪除一個元素。

          ConcurrentMap中有一個新的 putIfAbsent() 方法用于在 map 中進行添加。這個方法以要添加到 ConcurrentMap 實現中的鍵和值為參數,就像普通的 put() 方法,但是只有在 map 不包含這個鍵時,才能將鍵加入到 map 中。如果 map 已經包含這個鍵,那么這個鍵的現有值就會返回。這個操作等于清單9的代碼:

          if (!map.containsKey(key))

          return map.put(key, value);

          else

          return map.get(key);

           

          putIfAbsent() 方法一樣,重載后的 remove() 方法有兩個參數 —— 鍵和值。在調用時,只有當鍵映射到指定的值時才從 map 中刪除這個鍵。如果不匹配,那么就不刪除這個鍵,并返回 false。如果值匹配鍵的當前映射內容,那么就刪除這個鍵。清單 10 顯示了這種操作的等價源代碼:

           

          if (map.get(key).equals(value)) {

          map.remove(key);

          return true;

          } else {

          return false;

          }

          1.2.3.    CopyOnWriteArrayList CopyOnWriteArraySet

          copy-on-write 模式是這樣聲明的,為了維護對象的一致性快照,要依靠不可變性(immutability)來消除在協調讀取不同的但是相關的屬性時需要的同步。對于集合,這意味著如果有大量的讀(即 get() 和迭代,不必同步操作以照顧偶爾的寫(即 add())調用。對于新的 CopyOnWriteArrayList CopyOnWriteArraySet 類,所有可變的(mutable)操作都首先取得后臺數組的副本,對副本進行更改,然后替換副本。這種做法保證了在遍歷自身更改的集合時,永遠不會拋出 ConcurrentModificationException。遍歷集合會用原來的集合完成,而在以后的操作中使用更新后的集合。

          這些新的集合,CopyOnWriteArrayList CopyOnWriteArraySet,最適合于讀操作通常大大超過寫操作的情況。一個最常提到的例子是使用監聽器列表。已經說過,Swing 組件還沒有改為使用新的集合。相反,它們繼續使用 javax.swing.event.EventListenerList 來維護它們的監聽器列表。

          如清單11所示,集合的使用與它們的非 copy-on-write 替代物完全一樣。只是創建集合并在其中加入或者刪除元素。即使對象加入到了集合中,原來的 Iterator 也可以進行,繼續遍歷原來集合中的項。

           

          import java.util.*;

          import java.util.concurrent.*;

           

          public class CopyOnWrite {

            public static void main(String args[]) {

              List list1 = new CopyOnWriteArrayList(Arrays.asList(args));

              List list2 = new ArrayList(Arrays.asList(args));

              Iterator itor1 = list1.iterator();

              Iterator itor2 = list2.iterator();

              list1.add("New");

              list2.add("New");

              try {

                printAll(itor1);

              } catch (ConcurrentModificationException e) {

                System.err.println("Shouldn't get here");

              }

              try {

                printAll(itor2);

              } catch (ConcurrentModificationException e) {

                System.err.println("Will get here.");

              }

            }

            private static void printAll(Iterator itor) {

              while (itor.hasNext()) {

                System.out.println(itor.next());

              }

            }

          }

          這個示例程序用命令行參數創建 CopyOnWriteArrayList ArrayList 這兩個實例。在得到每一個實例的 Iterator 后,分別在其中加入一個元素。當 ArrayList 迭代因一個 ConcurrentModificationException 問題而立即停止時,CopyOnWriteArrayList 迭代可以繼續,不會拋出異常,因為原來的集合是在得到 iterator 之后改變的。如果這種行為(比如通知原來一組事件監聽器中的所有元素)是您需要的,那么最好使用 copy-on-write 集合。如果不使用的話,就還用原來的,并保證在出現異常時對它進行處理。

           

          1.3.        Formatter

          對于那些從一開始就使用 Java 編程而從沒有接觸過 C 的人,或者,對那些對 C 沒有足夠了解的人,格式化字符串是一些古怪的文本串,它們指定一組變量的輸出特性。不是用加號將字符串連接在一起(如 firstName + " " + lastName),而是提供一個字符串描述輸出,并提供參數以在方法調用結束時,替換字符串中的占位符:String s = String.format("%1$s %2$s", firstName, lastName)。

          首先,讓我們分析新的 java.util.Formatter 類。您可能不會經常直接使用這個類,但是它提供了所要進行的格式化的內部機制。在這個類的 Javadoc 中,會看到一個描述所支持的格式化選項的表。這些選項的范圍從以類似 %7.4f 這樣的格式指定浮點數的精度和位數,到格式化時間的 %tT,到格式化第三個參數 %3$s

          Formatter 格式化輸出分為兩步:創建一個 Appendable 對象以存儲輸出,用 format() 方法將帶格式的內容放到這個對象中。下面列出了 Appendable 接口的實現器:

           

          • BufferedWriter
          • CharArrayWriter
          • CharBuffer
          • FileWriter
          • FilterWriter
          • LogStream
          • OutputStreamWriter
          • PipedWriter
          • PrintStream
          • PrintWriter
          • StringBuffer
          • StringBuilder
          • StringWriter
          • Writer

           

          在使用 Formatter 類時,可以將實現了這個接口的對象傳遞給構造函數 Formatter 以把它作為目標。大多數這種類看起來很相似,除了 StringBuilder 類。StringBuilder StringBuffer 類幾乎相同,只有一個大的區別:它不是線程安全的。如果知道要在單線程中構建字符串,就使用 StringBuilder。如果構建過程會跨越多個線程,則使用 StringBuffer。清單12顯示了通常如何開始使用 Formatter

           

          StringBuilder sb = new StringBuilder();

          Formatter formatter = new Formatter(sb, Locale.US);

           

          創建了Formatter 類后,用格式化字符串和參數調用其 format() 方法。如果需要使用與傳遞給出構造函數的不同的 Locale 作為格式化輸出的一部分,還可以向 format() 方法傳遞一個 Locale 對象。清單 13 顯示了兩種不同的 format()

           

          public Formatter format(String format, Object... args)

          public Formatter format(Locale l, String format, Object... args)

           

          如果希望得到精度為 10 位數字的 Pi 值,清單 14 中的代碼會將這個值放到 StringBuilder 中并打印輸出。打印 formatter 對象將顯示 Appendable 對象的內容。

           

          import java.util.Locale;

          import java.util.Formatter;

           

          public class Build {

          public static void main(String args[]) {

          StringBuilder sb = new StringBuilder();

          Formatter formatter = new Formatter(sb, Locale.US);

          formatter.format("PI = %12.10f", Math.PI);

          System.out.println(formatter);

          }

          }

          1.3.1.    PrintStream支持

          PrintStream 類中定義了常見的、分別用于寫入標準輸出和標準錯誤的 System.out System.err 對象。Tiger 引入了兩個新的構造函數(用于直接寫入文件)和六個方法以提供對格式化的支持(三對)。第一對是另一版本的 append() 方法。這一對方法實現了新的 java.lang.Appendable 接口。一般不會直接調用這些方法。直接調用的是 format() printf(),其中 printf() 版本只是 format() 版本的方便的包裝器,如清單15所示:

           

          public PrintStream format(String format, Object... args)

          public PrintStream format(Locale l, String format, Object... args)

           

          要記住新的變量參數支持,它是由 ... 指派的

           

          清單16演示了用 PrintStream format() 方法打印今天的日期:

           

          import java.util.Calendar;

           

          public class Now {

              public static void main(String args[]) {

                  System.out.format("Today is %1$tB %1$te, %1$tY.",Calendar.getInstance());

              }

          }

           

          運行這個程序的輸出是 Today is January 19, 2005.,當然實際的輸出取決于運行這個程序的日期。上面代碼中的格式化字符串 %1$tB 告訴程序使用第一個參數并打印 date 對象的完整月名。格式化字符串 %1$te 意味著顯示月中的日期,而格式化字符串 %1$tY 是四位數字的年。在 Formatter 對象的 Javadoc 中列出了打印日期的其他選項。

          1.3.2.    String支持

          String 類有兩個新的 static format() 方法,它們的作用與相應的 printf() 類似。發送一個格式化字符串和參數(還可能有 Locale)、并使用在格式化字符串中指定的格式轉換參數。如果是這個方法的 String 版本,那么是以 String 對象而不是經過流返回結果。這些方法不是很顯眼,但是有了它們就可以避免直接使用 Formatter 對象并創建中間的 StringBuilder。

          1.3.3.    格式化任意對象

          到目前為止看到的每項內容都是描述如何使用新的格式化能力對已有對象和基本數據進行格式化。如果希望用 Formatter 提供對自己的對象的支持,那么就要用到 Formattable 接口。通過在自己的類中實現如清單 17 所示的一個 formatTo() 方法,可以對自已的類使用格式化字符串:

           

          void formatTo(Formatter formatter, int flags, Integer width, Integer precision)

           

          清單 18 演示了通過提供一個具有 name 屬性的簡單類來使用 Formattable 接口。這個 name 顯示在輸出中,它支持控制輸出的寬度和對齊。

           

          import java.util.Locale;

          import java.util.Formatter;

          import java.util.Formattable;

           

          public class MyObject implements Formattable {

            String name;

            public MyObject(String name) {

              this.name = name;

            }

            public void formatTo(

                   Formatter fmt,

                   int f,

                   Integer width,

                   Integer precision) {

           

              StringBuilder sb = new StringBuilder();

              if (precision == null) {

                // no max width

                sb.append(name);

              } else if (name.length() < precision) {

                sb.append(name);

              } else {

                sb.append(name.substring(0, precision - 1)).append('*');

              }

           

              // apply width and justification

              if ((width != null) && (sb.length() < width)) {

                for (int i = 0, n=sb.length(); i < width - n; i++) {

                  if ((f & Formattable.LEFT_JUSTIFY) == Formattable.LEFT_JUSTIFY) {

                    sb.append(' ');

                  } else {

                    sb.insert(0, ' ');

                  }

                }

              }

              fmt.format(sb.toString());

            }

           

            public static void main(String args[]) {

             MyObject my1 = new MyObject("John");

             MyObject my2 = new MyObject("Really Long Name");

             // First / Using toString()

             System.out.println("First Object : " + my1);

             // Second / Using Formatter

             System.out.format("First Object : '%s'\\n", my1);

             // Second / Using Formatter

             System.out.format("Second Object: '%s'\\n", my2);

             // Second / Using Formatter with width

             System.out.format("Second Object: '%10.5s'\\n", my2);

             // Second / Using Formatter with width and left justification

             System.out.format("Second Object: '%-10.5s'\\n", my2);

            }

          }

           

          運行這個程序會生成如清單19所示的輸出。前兩行展示了使用 toString Formatter 的不同結果。后三行顯示寬度和對齊控制的選項。

           

          First Object : MyObject@10b62c9

          First Object : 'John'

          Second Object: 'Really Long Name'

          Second Object: '     Real*'

          Second Object: 'Real*    

          1.4.        XML文件中裝載屬性

          Properties這個類對于讀者來說應該并不陌生,在應用程序的配置文件中大多采用的都是這樣的屬性文本文件。在Tiger中,java.util.Properties 類現在提供了一種為程序裝載和存儲設置的更容易的方法:loadFromXML(InputStream is) storeToXML(OutputStream os, String comment) 方法。

          1.4.1.    XML屬性文件

          XML屬性文件的指定DTD如清單20所示:

           

          <?xml version="1.0" encoding="UTF-8"?>

          <!-- DTD for properties -->

          <!ELEMENT properties ( comment?, entry* ) >

          <!ATTLIST properties version CDATA #FIXED "1.0">

          <!ELEMENT comment (#PCDATA) >

          <!ELEMENT entry (#PCDATA) >

          <!ATTLIST entry key CDATA #REQUIRED>

           

          簡單的XML屬性文件如清單21所示:

           

          <?xml version="1.0" encoding="UTF-8"?>

          <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">

          <properties>

          <comment>Hi</comment>

          <entry key="foo">bar</entry>

          <entry key="fu">baz</entry>

          </properties>

           

          相信讀者對此一目了然。

          1.4.2.    存取XML屬性文件

          1.4.2.1.        讀取XML屬性文件

          讀取 XML 版本的 Properties 文件與讀取老格式的文件沒什么不同。如清單22所示

           

          import java.util.*;

          import java.io.*;

           

          public class LoadSampleXML {

          public static void main(String args[]) throws Exception {

          Properties prop = new Properties();

          FileInputStream fis = new FileInputStream("sampleprops.xml");

          prop.loadFromXML(fis);

          prop.list(System.out);

          System.out.println("\nThe foo property: " + prop.getProperty("foo"));

          }

          }

          1.4.2.2.        保存XML屬性文件

          用新的 storeToXML() 方法創建xml文件。只要傳遞一個 OutputStream 和一個用于注釋的 String 就可以了。代碼如清單23所示:

           

          import java.util.*;

          import java.io.*;

           

          public class StoreXML {

          public static void main(String args[]) throws Exception {

          Properties prop = new Properties();

          prop.setProperty("one-two", "buckle my shoe");

          prop.setProperty("three-four", "shut the door");

          prop.setProperty("five-six", "pick up sticks");

          prop.setProperty("seven-eight", "lay them straight");

          prop.setProperty("nine-ten", "a big, fat hen");

          FileOutputStream fos = new FileOutputStream("rhyme.xml");

          prop.storeToXML(fos, "Rhyme");

          fos.close();

          }

          }

           

          運行結果如清單24所示:

           

          <?xml version="1.0" encoding="UTF-8"?>

          <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">

          <properties>

          <comment>Rhyme</comment>

          <entry key="seven-eight">lay them straight</entry>

          <entry key="five-six">pick up sticks</entry>

          <entry key="nine-ten">a big, fat hen</entry>

          <entry key="three-four">shut the door</entry>

          <entry key="one-two">buckle my shoe</entry>

          </properties>

          1.5.        其他核心庫的增強

          另外,Tiger以下核心庫方面也有了一定的增強,由于篇幅所限,這里就不一一贅述了,請感興趣的讀者參照JDK 5.0 API Documentation中的相關內容。

          1.5.1.    Scanner

          java.util.Scanner 類可用于將文本轉換成原語或字符串。由于它是基于 java.util.regex 包的,因此它也提供了一種方式來管理正則表達式,該表達式把搜索建立在流、文件數據、字符串或 Readable 接口的封裝行為(implementor)上。

          1.5.2.    JavaBeans組件體系結構

          已經添加了一個稱為 IndexedPropertyChangeEvent PropertyChangeEvent 子類來支持界限屬性,該屬性使用索引來指出 bean 的更改部分。另外,已經在 PropertyChangeSupport 類中添加了一些方法,用以支持激發索引屬性改變事件。

          1.5.3.    Math

          java.math 包包含了下面的增強功能:

          ·    BigDecimal 類已經為固定精度浮點計算添加了支持。參見 JSR 13.

          ·    Math StrictMath 庫包含雙曲線超越函數(sinh、cosh tanh)、立方根和基于 10 的對數等。

          ·    十六進制浮點數支持 —— 為允許特定浮點值的精確和可預知的說明,十六進制表示法可用于浮點數的字面值,以及用于 Float Double 中浮點數轉換方法的字符串。

          1.5.4.    網絡

          1.5.5.    安全性

          這一版本的 J2SE 在安全方面大大增強了。它為安全性令牌提供了更好的支持, 為更多的安全標準(SASL、OCSP TSP)提供了支持,改進了可伸縮性(SSLEngine)和性能,此外在 Crypto Java GSS 方面也提供了許多增強功能。有關更多信息,請參見上面的鏈接。

          1.5.6.    國際化

          增強功能有:

          ·    現在 字符處理是以 4.0 版本的 Unicode 標準為基礎的。這就影響了 java.lang 包中的 Character 類和 String 類、java.text 包中的排序規則和雙向文本分析功能、java.util.regex 包中的 Character 類及 J2SE 的其他許多部分。作為這一升級的一部分,JSR 204 專家組已經指定了對輔助字符的支持,而且在整個 J2SE 中已經實現了該支持。有關更多信息,請參見 JSR 204 Character 類文檔。

          ·    DecimalFormat 類已經得到了增強,現在可以格式化和解析 BigDecimal BigInteger 值,而不會丟失精確度。這些值的格式化是自動得到增強的;必須啟用 setParseBigDecimal 方法才可以進行到 BigDecimal 的解析。

          ·    現在,Vietnamese java.util java.text 包中所有的 Locale 敏感功能方面得到了支持。有關支持的 Locale 和寫系統的完整信息,請參見 支持的 Locale。

          1.5.7.    序列化

          已經添加了支持來處理 1.5 版本中新增的枚舉類型。序列化一個枚舉實例的規定不同于序列化一個普通可序列化對象的那些規則:枚舉實例的序列化表單只包括它的枚舉常量名和指出它的基本枚舉類型的信息。反序列化行為也是不同的 —— 類信息用于查找相應的枚舉類,并且為了獲取返回的枚舉常量,通過使用那個類和接收的常量名來調用 Enum.valueOf 方法。

          1.6.        結束語

          以上所講到的只是J2SE 15核心庫新特性的一小部分,還有很多其他新特性限于篇幅不能一一講述,有興趣進一步詳細了解這些新特性的讀者可以參看http://java.sun.com/j2se/1.5.0/docs/relnotes/features.html可獲取更多信息。

           

          Tiger“通過增強Java平臺的力量、允許開發者更容易地使用,Java編程語言的這些改進將吸引大量各種Java開發者,是“Java技術發展歷程的一個重要里程碑。

          posted on 2005-07-18 22:21 永琪 閱讀(151) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 吉林省| 布拖县| 札达县| 长宁区| 麻江县| 灵川县| 古浪县| 新昌县| 綦江县| 大洼县| 诸城市| 驻马店市| 宜阳县| 桂平市| 蒲江县| 花垣县| 双桥区| 锦屏县| 峨眉山市| 宜君县| 云阳县| 长宁区| 满洲里市| 久治县| 仁布县| 罗定市| 三河市| 巴南区| 清水河县| 大英县| 白城市| 岑溪市| 特克斯县| 汝城县| 报价| 朝阳县| 泗阳县| 麻城市| 宜君县| 乐山市| 黄平县|