Tiger核心库技术简介

news/2024/7/4 1:45:12 标签: properties, string, object, iterator, import, class
class="baidu_pl">
class="article_content clearfix">
class="htmledit_views">

class="a" style="MARGIN: 0cm 0cm 0pt">Tiger核心库简介

class="a0" style="MARGIN: 0cm 0cm 0pt">  

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.25pt; TEXT-ALIGN: right; punctuation-trim: leading" align="right">本文作者: 大阿福 (toafu2002@yahoo.com.cn )

class="MsoNormal" style="MARGIN: 0cm 64pt 0pt 0cm">  

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.1pt; mso-char-indent-count: 2.0">摘要:Java之所以得到很多程序员的亲睐,除了她的严谨的面向对象特性外,还有一个不容轻视的因素,那就是她强大的类库。一门语言如果没有库,功能将会大打折扣,在JDK5.0版本中,其核心库也有了诸多的改进,本文将就其新特性进行简介。

1.      访问环境变量和调用子进程

1.1       访问环境变量

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0">虽然Java从一开始推出的时候,就一再强调她的跨平台特性,“一次编译,到处运行”。所以能够访问平台专有信息的System.getenv()方法从一开始进入javalang包时,就遭到了大多数人的反对。虽然1.0版本中抛弃了其中的一些内容,但是在tiger版本中我们又可以使用这个方法了,请注意该方法的名称全部是小写。

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0">使用的方法很简单:如清单1

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">public class EnvTest {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 18pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">public static void main(String args[]) {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">System.out.println(System.getenv(args[0]));

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 18pt; TEXT-INDENT: 21pt">}

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">}

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0">  

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0">只要给定变量的名称,就可以得到它的当前值。

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0">  

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0">Tiger提供了两个版本的getenv(),第二个版本返回系统当前设置中所有的环境变量对应的“名值”对。清单2说明该方法的使用:

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">class="tags" href="/tags/IMPORT.html" title=import>import java.util.Map;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">public class EnvDump {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 18pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">public static void main(String args[]) {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">for (Map.Entry entry: System.getenv().entrySet()) {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 60pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">System.out.println(entry.getKey() + “/” + entry.getValue());

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: 21pt">}

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: 21pt">}

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 21pt">}

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0">  

1.2       访问子进程

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0">J2SE平台的前期版本提供了Runtime类的exec()方法用来创建子进程的运行,在Tiger版本中,这个方法依然有效,但是为了更方便的定制子进程,Tiger提供了ProcessBuilder类,它使依据改变了的进程变量来创建子进程更加便利。ProcessBuilder提供了directory(File)方法来改变进程的工作目录,用enviroment()方法在进程空间中添加和删除环境变量。清单3说明了Processor的简单用法,它使用 ipconfig 命令获得 Internet 配置信息。该方法适用于多数平台,否则可以将 ipconfig 改写成所用平台上的工作命令。启动进程构造程序之后,需要获得其 InputStream,以读入所创建进程的结果。

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">class="tags" href="/tags/IMPORT.html" title=import>import java.io.*;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">public class ProcessTest {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 18pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">public static void main(String args[]) throws IOException {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">Process p = new ProcessBuilder("ipconfig").start();

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">InputStream is = p.getInputStream();

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">BufferedReader br = new BufferedReader(new InputStreamReader(is));

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">String line;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">while ((line = br.readLine()) != null) {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 60pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">System.out.println(line);

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: 21pt">}

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 42pt">}

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 21pt">}

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0">  

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0">运行结果如清单4

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">Windows 2000 IP Configuration

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">Ethernet adapter 本地连接:

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">Connection-specific DNS Suffix  . :

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">        IP Address. . . . . . . . . . . . : 10.97.69.166

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: 21pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">Subnet Mask . . . . . . . . . . . : 255.255.255.128

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: 21pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">Default Gateway . . . . . . . . . : 10.97.69.129

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0">  

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 24pt; mso-char-indent-count: 2.0">ProcessBuilder 类不仅能生成新的进程,而且还能获得其结果。在调用其 start() 方法之前,还可以调整进程所执行的上下文。如果不喜欢环境变量,可以使用 environment 获得当前设置,并调用 clear() 清除映射。如果需要添加环境变量,可以调用 environment 获得当前设置,然后通过 put(name, value) 添加新的变量。如果希望使用新的工作目录,可以调用 directory() 并提供新的工作目录作为 File 对象。就是这么简单。

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0">使用表示将运行的命令及其参数的数目可变的字符串参数来创建 ProcessBuilder,一旦使用新的环境变量和工作目录配置 ProcessBuilder,就可以调用 start() 来执行命令。

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">  

2         并发集合

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">Java中的集合框架一直是令人津津乐道的,在Tiger中,集合框架新添加了Queue接口以及这个接口的并发和非并发实现,以及并发Map的实现和专用于读操作大大超过写操作的情况下的并发ListSet实现。

2.1     Queue接口

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">虽然在List的两端可以添加删除元素达到模拟queue的性能,但是Queue的提出提供了支持添加、删除和检查集合的更为方便的方法:如清单5所示

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">public boolean offer(Object element)

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">public Object remove()

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">public Object poll()

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">public Object element()

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">public Object peek()

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">一些队列有大小长度的限制,因此如果想在一个已满的队列中加入一个新项,多出的项就会被拒绝。这时新的 offer 方法就可以起作用了。它不是对调用 add() 方法抛出一个 unchecked 异常,而只是得到由 offer() 返回的 falseremove() poll() 方法都是从队列中删除第一个元素(head)。remove() 的行为与 Collection 接口的版本相似,但是新的 poll() 方法在用空集合调用时不是抛出异常,只是返回 null。因此新的方法更适合容易出现异常条件的情况。后两个方法 element() peek() 用于在队列的头部查询元素。与 remove() 方法类似,在队列为空时,element() 抛出一个异常,而 peek() 返回 null

2.1.1    基本队列实现

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt; TEXT-INDENT: -18pt; mso-list: l4 level1 lfo4; tab-stops: list 18.0pt">1、  Tiger中,java.util.LinkedList已经被改造为实现了java.util.Listjava.util.Queue两个接口。清单6显示的是LinkedList的简单使用:

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">  

         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
     

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">  

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt; TEXT-INDENT: -18pt; mso-list: l4 level1 lfo4; tab-stops: list 18.0pt">2、  util包新增加的AbstractQueue类,其工作方式类似于AbstractListAbstractSet类,在需要创建自己所需的对垒时,可以直接继承该类,必须实现offer()poll()peek()三个方法,读者可以在其中提供优化的实现。读者也可以不必创建自己的子类,而是使用几个tiger提供的实现,其中两个时不阻塞队列:PriorityQueueConcurrentLinkedQueuePriorityQueue类实际上是维护了一个有序的队列,加入到该Queue中的元素按照它们的自然顺序来进行排序,排序的依据是元素对java.util.Comparable的实现或者传递给该Queue构造函数的Comparator参数。如果将清单6的具体实现改为PriorityQueue,则输入的结果应该为Four,因为按字母顺序排列,Four是排在了第一个。ConcurrentLinkedQueue 是基于链接节点的、线程安全的队列。并发访问不需要同步。因为它在队列的尾部添加元素并从头部删除它们,所以只要不需要知道队列的大小,ConcurrentLinkedQueue 对公共集合的共享访问就可以工作得很好。收集关于队列大小的信息会很慢,需要遍历队列。

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 18pt; TEXT-INDENT: -18pt; mso-list: l4 level1 lfo4; tab-stops: list 18.0pt">3、   

2.1.2    阻塞队列实现

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">Tiger提供的 java.util.concurrent 包在 集合框架 中加入了 BlockingQueue 接口和五个阻塞队列类。简单的讲,阻塞队列的意思就是当队列无空间时,添加元素的线程执行操作阻塞,直到有空间;或者是,当队列为空无元素可删时,执行删除的线程阻塞,知道有元素可删。BlockingQueue 接口的 Javadoc 给出了阻塞队列的基本用法,如清单 7 所示。生产者中的 put() 操作会在没有空间可用时阻塞,而消费者的 take() 操作会在队列中没有任何东西时阻塞。

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">class Producer implements Runnable {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">   private final BlockingQueue queue;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">   Producer(BlockingQueue q) { queue = q; }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">   public void run() {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">     try {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">       while(true) { queue.put(produce()); }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">     } catch (InterruptedException ex) { ... handle ...}

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">   }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">   Object produce() { ... }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"> }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"> class Consumer implements Runnable {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">   private final BlockingQueue queue;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">   Consumer(BlockingQueue q) { queue = q; }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">   public void run() {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">     try {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">       while(true) { consume(queue.take()); }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">     } catch (InterruptedException ex) { ... handle ...}

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">   }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">   void consume(Object x) { ... }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"> }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"> class Setup {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">   void main() {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">     BlockingQueue q = new SomeQueueImplementation();

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">     Producer p = new Producer(q);

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">     Consumer c1 = new Consumer(q);

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">     Consumer c2 = new Consumer(q);

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">     new Thread(p).start();

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">     new Thread(c1).start();

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">     new Thread(c2).start();

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">   }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"> }

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">另外五个阻塞队列提供的情况各有不同:

  • class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; mso-list: l5 level1 lfo5; tab-stops: list 36.0pt">ArrayBlockingQueue:一个由数组支持的有界队列。
  • class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; mso-list: l5 level1 lfo5; tab-stops: list 36.0pt">LinkedBlockingQueue:一个由链接节点支持的可选有界队列。
  • class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; mso-list: l5 level1 lfo5; tab-stops: list 36.0pt">PriorityBlockingQueue:一个由优先级堆支持的无界优先级队列。
  • class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; mso-list: l5 level1 lfo5; tab-stops: list 36.0pt">DelayQueue:一个由优先级堆支持的、基于时间的调度队列。
  • class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; mso-list: l5 level1 lfo5; tab-stops: list 36.0pt">SynchronousQueue:一个利用 BlockingQueue 接口的简单聚集(rendezvous)机制

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">前两个类 ArrayBlockingQueue LinkedBlockingQueue 几乎相同,只是在底层存储实现方面有所不同,LinkedBlockingQueue 并不总是有容量界限。无大小界限的 LinkedBlockingQueue 类在添加元素时永远不会有阻塞队列的等待(至少在其中有 Integer.MAX_VALUE 元素之前不会,这个时候采用的容量限制即是Integer.MAX_VALUE)。

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">PriorityBlockingQueue 是具有无界限容量的队列,它利用所包含元素的 Comparable 排序顺序来以逻辑顺序维护元素。可以将它看作 TreeSet 的可能替代物。例如,在队列中加入字符串 OneTwoThree Four 会导致 Four 被第一个取出来。对于没有天然顺序的元素,可以为构造函数提供一个 Comparator 。不过对 PriorityBlockingQueue使用时需要注意,从 class="tags" href="/tags/ITERATOR.html" title=iterator>iterator() 返回的 Iterator 实例并不一定按照优先级顺序返回元素。如果必须以优先级顺序遍历所有元素,那么让它们都通过 toArray() 方法并自己对它们排序,像 Arrays.sort(pq.toArray())

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">新的 DelayQueue 实现可能是其中最有意思(也是最复杂)的一个。加入到队列中的元素必须实现新的 Delayed 接口(只有一个方法 —— long getDelay(java.util.concurrent.TimeUnit unit))。因为队列的大小没有界限,使得添加可以立即返回,但是在延迟时间过去之前,不能从队列中取出元素。如果多个元素完成了延迟,那么最早失效/失效时间最长的元素将第一个取出。实际上没有听上去这样复杂。清单8演示了这种新的阻塞队列集合的使用:

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">class="tags" href="/tags/IMPORT.html" title=import>import java.util.*;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">class="tags" href="/tags/IMPORT.html" title=import>import java.util.concurrent.*;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">public class Delay {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  /**

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">   * Delayed implementation that actually delays

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">   */

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  static class NanoDelay implements Delayed {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    long trigger;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    NanoDelay(long i) {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">      trigger = System.nanoTime() + i;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    public int compareTo(Object y) {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">      long i = trigger;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">      long j = ((NanoDelay)y).trigger;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">      if (i < j) return -1;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">      if (i > j) return 1;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">      return 0;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    public boolean equals(Object other) {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">      return ((NanoDelay)other).trigger == trigger;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    public boolean equals(NanoDelay other) {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">      return other.trigger == trigger;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    public long getDelay(TimeUnit unit) {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">      long n = trigger - System.nanoTime();

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">      return unit.convert(n, TimeUnit.NANOSECONDS);

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    public long getTriggerTime() {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">      return trigger;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    public String toString() {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">      return String.valueOf(trigger);

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  public static void main(String args[]) throws InterruptedException {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    Random random = new Random();

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    DelayQueue queue = new DelayQueue();

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    for (int i=0; i < 5; i++) {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">      queue.add(new NanoDelay(random.nextInt(1000)));

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    long last = 0;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    for (int i=0; i < 5; i++) {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">      NanoDelay delay = (NanoDelay)(queue.take());

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">      long tt = delay.getTriggerTime();

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">      System.out.println("Trigger time: " + tt);

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">      if (i != 0) {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">        System.out.println("Delta: " + (tt - last));

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">      }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">      last = tt;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">}

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">这个例子首先是一个内部类 NanoDelay,它实质上将暂停给定的任意纳秒(nanosecond)数,这里利用了 System 的新 nanoTime() 方法。然后 main() 方法只是将 NanoDelay 对象放到队列中并再次将它们取出来。如果希望队列项做一些其他事情,就需要在 Delayed 对象的实现中加入方法,并在从队列中取出后调用这个新方法。(请随意扩展 NanoDelay 以试验加入其他方法做一些有趣的事情。)显示从队列中取出元素的两次调用之间的时间差。如果时间差是负数,可以视为一个错误,因为永远不会在延迟时间结束后,在一个更早的触发时间从队列中取得项。

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">SynchronousQueue 类是最简单的。它没有内部容量。它就像线程之间的手递手机制。在队列中加入一个元素的生产者会等待另一个线程的消费者。当这个消费者出现时,这个元素就直接在消费者和生产者之间传递,永远不会加入到阻塞队列中

2.2     ConcurrentMap实现

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">新的 java.util.concurrent.ConcurrentMap 接口和 ConcurrentHashMap 实现只能在键不存在时将元素加入到 map 中,只有在键存在并映射到特定值时才能从 map 中删除一个元素。

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">ConcurrentMap中有一个新的 putIfAbsent() 方法用于在 map 中进行添加。这个方法以要添加到 ConcurrentMap 实现中的键和值为参数,就像普通的 put() 方法,但是只有在 map 不包含这个键时,才能将键加入到 map 中。如果 map 已经包含这个键,那么这个键的现有值就会返回。这个操作等于于清单9的代码:

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">if (!map.containsKey(key))

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: 21pt">return map.put(key, value);

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">else

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: 21pt">return map.get(key);

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"> putIfAbsent() 方法一样,重载后的 remove() 方法有两个参数 —— 键和值。在调用时,只有当键映射到指定的值时才从 map 中删除这个键。如果不匹配,那么就不删除这个键,并返回 false。如果值匹配键的当前映射内容,那么就删除这个键。清单 10 显示了这种操作的等价源代码:

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">if (map.get(key).equals(value)) {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: 21pt">map.remove(key);

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: 21pt">return true;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">} else {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: 21pt">return false;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">}

class="atitle21">2.3   class="atitle21">CopyOnWriteArrayList class="atitle21">class="atitle21"> CopyOnWriteArraySetclass="atitle21">

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">copy-on-write 模式是这样声明的,为了维护对象的一致性快照,要依靠不可变性(immutability)来消除在协调读取不同的但是相关的属性时需要的同步。对于集合,这意味着如果有大量的读(即 get() 和迭代,不必同步操作以照顾偶尔的写(即 add())调用。对于新的 CopyOnWriteArrayList CopyOnWriteArraySet 类,所有可变的(mutable)操作都首先取得后台数组的副本,对副本进行更改,然后替换副本。这种做法保证了在遍历自身更改的集合时,永远不会抛出 ConcurrentModificationException。遍历集合会用原来的集合完成,而在以后的操作中使用更新后的集合。

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">这些新的集合,CopyOnWriteArrayList CopyOnWriteArraySet,最适合于读操作通常大大超过写操作的情况。一个最常提到的例子是使用监听器列表。已经说过,Swing 组件还没有改为使用新的集合。相反,它们继续使用 javax.swing.event.EventListenerList 来维护它们的监听器列表。

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">如清单11所示,集合的使用与它们的非 copy-on-write 替代物完全一样。只是创建集合并在其中加入或者删除元素。即使对象加入到了集合中,原来的 Iterator 也可以进行,继续遍历原来集合中的项。

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">class="tags" href="/tags/IMPORT.html" title=import>import java.util.*;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">class="tags" href="/tags/IMPORT.html" title=import>import java.util.concurrent.*;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">public class CopyOnWrite {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  public static void main(String args[]) {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    List list1 = new CopyOnWriteArrayList(Arrays.asList(args));

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    List list2 = new ArrayList(Arrays.asList(args));

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    Iterator itor1 = list1.class="tags" href="/tags/ITERATOR.html" title=iterator>iterator();

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    Iterator itor2 = list2.class="tags" href="/tags/ITERATOR.html" title=iterator>iterator();

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    list1.add("New");

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    list2.add("New");

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    try {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">      printAll(itor1);

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    } catch (ConcurrentModificationException e) {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">      System.err.println("Shouldn't get here");

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    try {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">      printAll(itor2);

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    } catch (ConcurrentModificationException e) {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">      System.err.println("Will get here.");

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  private static void printAll(Iterator itor) {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    while (itor.hasNext()) {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">      System.out.println(itor.next());

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">    }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">}

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">这个示例程序用命令行参数创建 CopyOnWriteArrayList ArrayList 这两个实例。在得到每一个实例的 Iterator 后,分别在其中加入一个元素。当 ArrayList 迭代因一个 ConcurrentModificationException 问题而立即停止时,CopyOnWriteArrayList 迭代可以继续,不会抛出异常,因为原来的集合是在得到 class="tags" href="/tags/ITERATOR.html" title=iterator>iterator 之后改变的。如果这种行为(比如通知原来一组事件监听器中的所有元素)是您需要的,那么最好使用 copy-on-write 集合。如果不使用的话,就还用原来的,并保证在出现异常时对它进行处理。

3         Formatter

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">对于那些从一开始就使用 Java 编程而从没有接触过 C 的人,或者,对那些对 C 没有足够了解的人,格式化字符串是一些古怪的文本串,它们指定一组变量的输出特性。不是用加号将字符串连接在一起(如 firstName + " " + lastName),而是提供一个字符串描述输出,并提供参数以在方法调用结束时,替换字符串中的占位符:String s = String.format("%1$s %2$s", firstName, lastName)

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">首先,让我们分析新的 java.util.Formatter 类。您可能不会经常直接使用这个类,但是它提供了所要进行的格式化的内部机制。在这个类的 Javadoc 中,会看到一个描述所支持的格式化选项的表。这些选项的范围从以类似 % 7.4f 这样的格式指定浮点数的精度和位数,到格式化时间的 %tT,到格式化第三个参数 %3$s

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"> Formatter 格式化输出分为两步:创建一个 Appendable 对象以存储输出,用 format() 方法将带格式的内容放到这个对象中。下面列出了 Appendable 接口的实现器:

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

  • class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; mso-list: l2 level1 lfo6; tab-stops: list 36.0pt">BufferedWriter
  • class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; mso-list: l2 level1 lfo6; tab-stops: list 36.0pt">CharArrayWriter
  • class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; mso-list: l2 level1 lfo6; tab-stops: list 36.0pt">CharBuffer
  • class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; mso-list: l2 level1 lfo6; tab-stops: list 36.0pt">FileWriter
  • class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; mso-list: l2 level1 lfo6; tab-stops: list 36.0pt">FilterWriter
  • class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; mso-list: l2 level1 lfo6; tab-stops: list 36.0pt">LogStream
  • class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; mso-list: l2 level1 lfo6; tab-stops: list 36.0pt">OutputStreamWriter
  • class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; mso-list: l2 level1 lfo6; tab-stops: list 36.0pt">PipedWriter
  • class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; mso-list: l2 level1 lfo6; tab-stops: list 36.0pt">PrintStream
  • class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; mso-list: l2 level1 lfo6; tab-stops: list 36.0pt">PrintWriter
  • class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; mso-list: l2 level1 lfo6; tab-stops: list 36.0pt">StringBuffer
  • class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; mso-list: l2 level1 lfo6; tab-stops: list 36.0pt">StringBuilder
  • class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; mso-list: l2 level1 lfo6; tab-stops: list 36.0pt">StringWriter
  • class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; mso-list: l2 level1 lfo6; tab-stops: list 36.0pt">Writer

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">在使用 Formatter 类时,可以将实现了这个接口的对象传递给构造函数 Formatter 以把它作为目标。大多数这种类看起来很相似,除了 StringBuilder 类。StringBuilder StringBuffer 类几乎相同,只有一个大的区别:它不是线程安全的。如果知道要在单线程中构建字符串,就使用 StringBuilder。如果构建过程会跨越多个线程,则使用 StringBuffer。清单12显示了通常如何开始使用 Formatter

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">StringBuilder sb = new StringBuilder();

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">Formatter formatter = new Formatter(sb, Locale.US);

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">创建了Formatter 类后,用格式化字符串和参数调用其 format() 方法。如果需要使用与传递给出构造函数的不同的 Locale 作为格式化输出的一部分,还可以向 format() 方法传递一个 Locale 对象。清单 13 显示了两种不同的 format()

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">public Formatter format(String format, Object... args)

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">public Formatter format(Locale l, String format, Object... args)

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">如果希望得到精度为 10 位数字的 Pi 值,清单 14 中的代码会将这个值放到 StringBuilder 中并打印输出。打印 formatter 对象将显示 Appendable 对象的内容。

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">class="tags" href="/tags/IMPORT.html" title=import>import java.util.Locale;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">class="tags" href="/tags/IMPORT.html" title=import>import java.util.Formatter;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">public class Build {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: 21pt">public static void main(String args[]) {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: 21pt">StringBuilder sb = new StringBuilder();

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: 21pt">Formatter formatter = new Formatter(sb, Locale.US);

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: 21pt">formatter.format("PI = % 12.10f ", Math.PI);

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: 21pt">System.out.println(formatter);

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: 21pt">}

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">}

3.1     PrintStream支持

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">PrintStream 类中定义了常见的、分别用于写入标准输出和标准错误的 System.out System.err 对象。Tiger 引入了两个新的构造函数(用于直接写入文件)和六个方法以提供对格式化的支持(三对)。第一对是另一版本的 append() 方法。这一对方法实现了新的 java.lang.Appendable 接口。一般不会直接调用这些方法。直接调用的是 format() printf(),其中 printf() 版本只是 format() 版本的方便的包装器,如清单15所示:

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">public PrintStream format(String format, Object... args)

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">public PrintStream format(Locale l, String format, Object... args)

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">要记住新的变量参数支持,它是由 ... 指派的

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">清单16演示了用 PrintStream format() 方法打印今天的日期:

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">class="tags" href="/tags/IMPORT.html" title=import>import java.util.Calendar;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">public class Now {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">     public static void main(String args[]) {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">         System.out.format("Today is %1$tB %1$te, %1$tY.",Calendar.getInstance());

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">     }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">}

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">运行这个程序的输出是 Today is January 19, 2005.,当然实际的输出取决于运行这个程序的日期。上面代码中的格式化字符串 %1$tB 告诉程序使用第一个参数并打印 date 对象的完整月名。格式化字符串 %1$te 意味着显示月中的日期,而格式化字符串 %1$tY 是四位数字的年。在 Formatter 对象的 Javadoc 中列出了打印日期的其他选项。

3.2     String支持

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">String 类有两个新的 static format() 方法,它们的作用与相应的 printf() 类似。发送一个格式化字符串和参数(还可能有 Locale)、并使用在格式化字符串中指定的格式转换参数。如果是这个方法的 String 版本,那么是以 String 对象而不是经过流返回结果。这些方法不是很显眼,但是有了它们就可以避免直接使用 Formatter 对象并创建中间的 StringBuilder

3.3     格式化任意对象

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">到目前为止看到的每项内容都是描述如何使用新的格式化能力对已有对象和基本数据进行格式化。如果希望用 Formatter 提供对自己的对象的支持,那么就要用到 Formattable 接口。通过在自己的类中实现如清单 17 所示的一个 formatTo() 方法,可以对自已的类使用格式化字符串:

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">void formatTo(Formatter formatter, int flags, Integer width, Integer precision)

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">清单 18 演示了通过提供一个具有 name 属性的简单类来使用 Formattable 接口。这个 name 显示在输出中,它支持控制输出的宽度和对齐。

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">class="tags" href="/tags/IMPORT.html" title=import>import java.util.Locale;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">class="tags" href="/tags/IMPORT.html" title=import>import java.util.Formatter;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">class="tags" href="/tags/IMPORT.html" title=import>import java.util.Formattable;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">public class MyObject implements Formattable {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">  String name;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">  public MyObject(String name) {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">    this.name = name;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">  }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">  public void formatTo(

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">         Formatter fmt,

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">         int f,

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">         Integer width,

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">         Integer precision) {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">    StringBuilder sb = new StringBuilder();

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">    if (precision == null) {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">      // no max width

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">      sb.append(name);

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">    } else if (name.length() < precision) {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">      sb.append(name);

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">    } else {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">      sb.append(name.subclass="tags" href="/tags/STRING.html" title=string>string(0, precision - 1)).append('*');

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">    }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">    // apply width and justification

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">    if ((width != null) && (sb.length() < width)) {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">      for (int i = 0, n=sb.length(); i < width - n; i++) {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">        if ((f & Formattable.LEFT_JUSTIFY) == Formattable.LEFT_JUSTIFY) {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">          sb.append(' ');

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">        } else {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">          sb.insert(0, ' ');

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">        }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">      }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">    }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">    fmt.format(sb.toString());

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">  }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">  public static void main(String args[]) {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">   MyObject my1 = new MyObject("John");

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">   MyObject my2 = new MyObject("Really Long Name");

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">   // First / Using toString()

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">   System.out.println("First Object : " + my1);

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">   // Second / Using Formatter

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">   System.out.format("First Object : '%s'//n", my1);

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">   // Second / Using Formatter

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">   System.out.format("Second Object: '%s'//n", my2);

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">   // Second / Using Formatter with width

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">   System.out.format("Second Object: '%10.5s'//n", my2);

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">   // Second / Using Formatter with width and left justification

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">   System.out.format("Second Object: '%-10.5s'//n", my2);

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">  }

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">}

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">运行这个程序会生成如清单19所示的输出。前两行展示了使用 toString Formatter 的不同结果。后三行显示宽度和对齐控制的选项。

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">First Object : MyObject@10b 62c 9

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">First Object : 'John'

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">Second Object: 'Really Long Name'

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">Second Object: '     Real*'

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0">Second Object: 'Real*    

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

4         XML文件中装载属性

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">Properties这个类对于读者来说应该并不陌生,在应用程序的配置文件中大多采用的都是这样的属性文本文件。在Tiger中,java.util.Properties 类现在提供了一种为程序装载和存储设置的更容易的方法:loadFromXML(InputStream is) storeToXML(OutputStream os, String comment) 方法。

4.1     XML属性文件

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">XML属性文件的指定DTD如清单20所示:

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0"><?xml version="1.0" encoding="UTF-8"?>

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0"><!-- DTD for class="tags" href="/tags/PROPERTIES.html" title=properties>properties -->

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0"><!ELEMENT class="tags" href="/tags/PROPERTIES.html" title=properties>properties ( comment?, entry* ) >

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0"><!ATTLIST class="tags" href="/tags/PROPERTIES.html" title=properties>properties version CDATA #FIXED "1.0">

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0"><!ELEMENT comment (#PCDATA) >

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0"><!ELEMENT entry (#PCDATA) >

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0"><!ATTLIST entry key CDATA #REQUIRED>

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">简单的XML属性文件如清单21所示:

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0"><?xml version="1.0" encoding="UTF-8"?>

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0"><!DOCTYPE class="tags" href="/tags/PROPERTIES.html" title=properties>properties SYSTEM "http://java.sun.com/dtd/class="tags" href="/tags/PROPERTIES.html" title=properties>properties.dtd">

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0"><class="tags" href="/tags/PROPERTIES.html" title=properties>properties>

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0"><comment>Hi</comment>

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0"><entry key="foo">bar</entry>

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0"><entry key="fu">baz</entry>

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt; mso-char-indent-count: 2.0"></class="tags" href="/tags/PROPERTIES.html" title=properties>properties>

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">相信读者对此一目了然。

4.2     存取XML属性文件

4.2.1    读取XML属性文件

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">读取 XML 版本的 Properties 文件与读取老格式的文件没什么不同。如清单22所示

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">import java.util.*;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">class="tags" href="/tags/IMPORT.html" title=import>import java.io.*;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">public class LoadSampleXML {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: 21pt">public static void main(String args[]) throws Exception {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: 21pt">Properties prop = new Properties();

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: 21pt">FileInputStream fis = new FileInputStream("sampleprops.xml");

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: 21pt">prop.loadFromXML(fis);

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: 21pt">prop.list(System.out);

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: 21pt">System.out.println("/nThe foo property: " + prop.getProperty("foo"));

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: 21pt">}

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">}

4.2.2    保存XML属性文件

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">用新的 storeToXML() 方法创建xml文件。只要传递一个 OutputStream 和一个用于注释的 String 就可以了。代码如清单23所示:

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">class="tags" href="/tags/IMPORT.html" title=import>import java.util.*;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">class="tags" href="/tags/IMPORT.html" title=import>import java.io.*;

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">public class StoreXML {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: 21pt">public static void main(String args[]) throws Exception {

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: 21pt">Properties prop = new Properties();

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: 21pt">prop.setProperty("one-two", "buckle my shoe");

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: 21pt">prop.setProperty("three-four", "shut the door");

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: 21pt">prop.setProperty("five-six", "pick up sticks");

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: 21pt">prop.setProperty("seven-eight", "lay them straight");

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: 21pt">prop.setProperty("nine-ten", "a big, fat hen");

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: 21pt">FileOutputStream fos = new FileOutputStream("rhyme.xml");

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: 21pt">prop.storeToXML(fos, "Rhyme");

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: 21pt">fos.close();

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: 21pt">}

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">}

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">运行结果如清单24所示:

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><?xml version="1.0" encoding="UTF-8"?>

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><!DOCTYPE class="tags" href="/tags/PROPERTIES.html" title=properties>properties SYSTEM "http://java.sun.com/dtd/class="tags" href="/tags/PROPERTIES.html" title=properties>properties.dtd">

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><class="tags" href="/tags/PROPERTIES.html" title=properties>properties>

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><comment>Rhyme</comment>

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><entry key="seven-eight">lay them straight</entry>

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><entry key="five-six">pick up sticks</entry>

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><entry key="nine-ten">a big, fat hen</entry>

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><entry key="three-four">shut the door</entry>

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><entry key="one-two">buckle my shoe</entry>

class="MsoNormal" style="BACKGROUND: #cccccc; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"></class="tags" href="/tags/PROPERTIES.html" title=properties>properties>

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">  

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">  

5         其他核心库的增强

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 31.5pt">另外,Tiger以下核心库方面也有了一定的增强,由于篇幅所限,这里就不一一赘述了,请感兴趣的读者参照JDK 5.0 API Documentation中的相关内容。

5.1     Scanner

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">java.util.Scanner 类可用于将文本转换成原语或字符串。由于它是基于 java.util.regex 包的,因此它也提供了一种方式来管理正则表达式,该表达式把搜索建立在流、文件数据、字符串或 Readable 接口的封装行为(implementor)上。

5.2     JavaBeans组件体系结构

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">已经添加了一个称为 IndexedPropertyChangeEvent PropertyChangeEvent 子类来支持界限属性,该属性使用索引来指出 bean 的更改部分。另外,已经在 PropertyChangeSupport 类中添加了一些方法,用以支持激发索引属性改变事件。

5.3     Math

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 20pt; TEXT-ALIGN: left" align="left">java.math 包包含了下面的增强功能:

class="a1" style="MARGIN: 0cm 0cm 0pt 31.45pt; LINE-HEIGHT: 20pt; mso-line-height-rule: exactly">·    BigDecimal 类已经为固定精度浮点计算添加了支持。参见 JSR 13.

class="a1" style="MARGIN: 0cm 0cm 0pt 31.45pt; LINE-HEIGHT: 20pt; mso-line-height-rule: exactly">·    Math StrictMath 库包含双曲线超越函数(sinhcosh tanh)、立方根和基于 10 的对数等。

class="a1" style="MARGIN: 0cm 0cm 0pt 31.45pt; LINE-HEIGHT: 20pt; mso-line-height-rule: exactly">·    十六进制浮点数支持 —— 为允许特定浮点值的精确和可预知的说明,十六进制表示法可用于浮点数的字面值,以及用于 Float Double 中浮点数转换方法的字符串。

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">  

5.4     网络

5.5     安全性

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">这一版本的 J2SE 在安全方面大大增强了。它为安全性令牌提供了更好的支持, 为更多的安全标准(SASLOCSP TSP)提供了支持,改进了可伸缩性(SSLEngine)和性能,此外在 Crypto Java GSS 方面也提供了许多增强功能。有关更多信息,请参见上面的链接。

5.6     国际化

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; TEXT-ALIGN: left" align="left">增强功能有:

class="a1" style="MARGIN: 0cm 0cm 0pt 31.45pt; LINE-HEIGHT: 20pt; mso-line-height-rule: exactly">·    现在 字符处理是以 4.0 版本的 Unicode 标准为基础的。这就影响了 java.lang 包中的 Character 类和 String 类、java.text 包中的排序规则和双向文本分析功能、java.util.regex 包中的 Character 类及 J2SE 的其他许多部分。作为这一升级的一部分,JSR 204 专家组已经指定了对辅助字符的支持,而且在整个 J2SE 中已经实现了该支持。有关更多信息,请参见 JSR 204 Character 类文档。

class="a1" style="MARGIN: 0cm 0cm 0pt 31.45pt; LINE-HEIGHT: 20pt; mso-line-height-rule: exactly">·    DecimalFormat 类已经得到了增强,现在可以格式化和解析 BigDecimal BigInteger 值,而不会丢失精确度。这些值的格式化是自动得到增强的;必须启用 setParseBigDecimal 方法才可以进行到 BigDecimal 的解析。

class="a1" style="MARGIN: 0cm 0cm 0pt 31.45pt; LINE-HEIGHT: 20pt; mso-line-height-rule: exactly">·    现在,Vietnamese java.util java.text 包中所有的 Locale 敏感功能方面得到了支持。有关支持的 Locale 和写系统的完整信息,请参见 支持的 Locale

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">  

5.7     序列化

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">已经添加了支持来处理 1.5 版本中新增的枚举类型。序列化一个枚举实例的规定不同于序列化一个普通可序列化对象的那些规则:枚举实例的序列化表单只包括它的枚举常量名和指出它的基本枚举类型的信息。反序列化行为也是不同的 —— 类信息用于查找相应的枚举类,并且为了获取返回的枚举常量,通过使用那个类和接收的常量名来调用 Enum.valueOf 方法。

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">  

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">  

6         结束语

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt">以上所讲到的只是J2SE 15核心库新特性的一小部分,还有很多其他新特性限于篇幅不能一一讲述,有兴趣进一步详细了解这些新特性的读者可以参看http://java.sun.com/j2se/ 1.5.0 /docs/relnotes/features.html可获取更多信息。

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt">  

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt">Tiger“通过增强Java平台的力量、允许开发者更容易地使用,Java编程语言的这些改进将吸引大量各种Java开发者,是“Java技术发展历程的一个重要里程碑

class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt">  


http://www.niftyadmin.cn/n/1801437.html

相关文章

ASP.NET 2.0中的跨页面提交

ASP.NET 2.0中的跨页面提交 简介在ASP.NET 1.X 版本中&#xff0c;页面都是提交到自己本身&#xff0c;并不能方便的指定需要提交的目的页面。例如FirstPage.aspx中的button只能提交到FirstPage.aspx&#xff0c;而不能提交到SecondPage.aspx。很多时候&#xff0c;ASP.NET 1.X…

第2章第2节练习题2 使用栈模拟队列操作

问题描述 利用两个栈S1&#xff0c;S2来模拟一个队列&#xff0c;已知栈的4的运算定义如下&#xff1a; Push(S,x); 元素x入栈S Pop(S,x); S出栈并将出栈的值赋给x StackEmpty(S); 判断栈是否为空 StackOverflow(S); 判断栈是否满 Enqueue; 将元素x入队 Dequeue; 出队&…

RichClient技术简介

Rich Client技术简介2承前正如前文所介绍的&#xff0c;传统的基于C/S的Windows应用程序总是让客户面临着一些感觉很是不爽的问题&#xff0c;如&#xff1a;部署问题、升级困难、维护困难、安全问题&#xff0c;但是完全的WEB开发由于HTTP协议的无状态特性——浏览器和服务器总…

更新ebuild

今天编译tomcat&#xff0c;但是其中的一个包需要使用jdk-1.4.2&#xff0c;而我用的是jdk-1.5&#xff0c;于是就修改它&#xff0c;改完后要更新MD5&#xff1a;ebuild XXX.ebuild digest

新的一年即将开始,先总结这一年

这是工作后的第一个新年&#xff0c;也是我第一次不会回家的新年。 看着朋友同事们的仓惶离去&#xff0c;坐在平时拥挤不堪而现在冷清空当的公车上&#xff0c;心中不免凄凉。2004年&#xff0c;我毕业了收获&#xff1a;1、作为应届生进入国内一著名大型软件公司工作&#xf…

第2章第2节练习题3 使用队列模拟渡口管理

问题描述 汽车轮渡口&#xff0c;过江渡船每次能载10辆车过江。过江车分为客车和货车类&#xff0c;上渡船有如下规定&#xff1a; 1).同类车先到先上船&#xff1b; 2).客车先于货车上渡船&#xff0c;其每上4辆客车&#xff0c;才允许放上一辆货车&#xff1b; 3).若等待客…

知识的积累(转载自梦想风暴)

最初认识Darwin的时候&#xff0c;我还是个没毕业的新手。那时&#xff0c;我在公司做毕业设计&#xff0c;题目就是用C对部门内已有的一套C的库进行封装。那套库就是Darwin开发的&#xff0c;这次封装工作也是在他的领导之下进行的。当时&#xff0c;我对C有着说不清的好感&am…

第2章第3节 串

关于串的基本定义已经在第2章栈和队列以及串中介绍过了&#xff0c;与栈和队列类似&#xff0c;同样存在顺序结构存储的串&#xff08;这里简称顺序串&#xff09;和链式结构存储的串&#xff08;这里简称链串&#xff09;。 一.顺序串 1.1定义 串的顺序实现是指分配一块连续…