一個(gè)程序員的爛筆頭兒

          記錄前進(jìn)路上的每一個(gè)腳印

           

          轉(zhuǎn)載:jdk5.0新特性

          以下是網(wǎng)上摘錄的: JDK5.0的新特性(2005-2006)
          “JDK1.5”(開發(fā)代號(hào)猛虎)的一個(gè)重要主題就是通過(guò)新增一些特性來(lái)簡(jiǎn)化開發(fā),
          這些特性包括泛型,for-each 循環(huán),自動(dòng)裝包/拆包,枚舉,可變參數(shù), 靜態(tài)導(dǎo)入
          C 風(fēng)格的格式化 I/O、、并發(fā)實(shí)用程序以及更簡(jiǎn)單的 RMI 接口生成。
          JSR 201 包括如下四個(gè)語(yǔ)言變化:增強(qiáng)的 for 循環(huán)、枚舉類型、靜態(tài)導(dǎo)入和 autoboxing;JSR 175 指定了新的元數(shù)據(jù)功能,而 JSR 14 則詳細(xì)說(shuō)明了泛型。
          javac 編譯器執(zhí)行的默認(rèn)語(yǔ)言規(guī)范是版本 1.4。這意味著要利用以下語(yǔ)言變化的任何好處,需要向 javac 命令傳遞參數(shù) -source 1.5。
          使用這些特性有助于我們編寫更加清晰,精悍,安全的代碼。
            下面我們簡(jiǎn)單介紹一下這些新特性。
            1.泛型(Generic)
            C++通過(guò)模板技術(shù)可以指定集合的元素類型,而Java在1.5之前一直沒(méi)有相對(duì)應(yīng)的功
          能。一個(gè)集合可以放任何類型的對(duì)象,相應(yīng)地從集合里面拿對(duì)象的時(shí)候我們也不得不對(duì)
          他們進(jìn)行強(qiáng)制得類型轉(zhuǎn)換。猛虎引入了泛型,它允許指定集合里元素的類型,這樣你可
          以得到強(qiáng)類型在編譯時(shí)刻進(jìn)行類型檢查的好處。
           
          Collection c = new ArrayList();
          c.add(new Date());
           
            編譯器會(huì)給出一個(gè)錯(cuò)誤:
           
          add(java.lang.String) in java.util.Collection cannot be applied to 
          (java.util.Date)
           
            2.For-Each循環(huán)
            For-Each循環(huán)得加入簡(jiǎn)化了集合的遍歷。假設(shè)我們要遍歷一個(gè)集合對(duì)其中的元素進(jìn)
          行一些處理。典型的代碼為:
           
          void processAll(Collection c){
              for(Iterator i=c.iterator(); i.hasNext();){
                  MyClass myObject = (MyClass)i.next();
                  myObject.process();
              }
          }
           
            使用For-Each循環(huán),我們可以把代碼改寫成:
           
          void processAll(Collection c){
              for (MyClass  myObject :c)
                  myObject.process();
          }
           
            這段代碼要比上面清晰許多,并且避免了強(qiáng)制類型轉(zhuǎn)換。
            3.自動(dòng)裝包/拆包(Autoboxing/unboxing)
            自動(dòng)裝包/拆包大大方便了基本類型數(shù)據(jù)和它們包裝類地使用。
            自動(dòng)裝包:基本類型自動(dòng)轉(zhuǎn)為包裝類.(int >> Integer)
            自動(dòng)拆包:包裝類自動(dòng)轉(zhuǎn)為基本類型.(Integer >> int)
            在JDK1.5之前,我們總是對(duì)集合不能存放基本類型而耿耿于懷,現(xiàn)在自動(dòng)轉(zhuǎn)換機(jī)制
          解決了我們的問(wèn)題。
          int a = 3;
          Collection c = new ArrayList();
          c.add(a);//自動(dòng)轉(zhuǎn)換成Integer.
          Integer b = new Integer(2);
          c.add(b + 2);
            這里Integer先自動(dòng)轉(zhuǎn)換為int進(jìn)行加法運(yùn)算,然后int再次轉(zhuǎn)換為Integer.
            4.枚舉(Enums)
            JDK1.5加入了一個(gè)全新類型的“類”-枚舉類型。為此JDK1.5引入了一個(gè)新關(guān)鍵字
          enmu. 我們可以這樣來(lái)定義一個(gè)枚舉類型。
           
          public enum Color
          {
             Red,
             White,
             Blue
          }
            然后可以這樣來(lái)使用Color myColor = Color.Red.
            枚舉類型還提供了兩個(gè)有用的靜態(tài)方法values()和valueOf(). 我們可以很方便地
          使用它們,例如
          for (Color c : Color.values())
                      System.out.println(c);
            5.可變參數(shù)(Varargs)
            可變參數(shù)使程序員可以聲明一個(gè)接受可變數(shù)目參數(shù)的方法。注意,可變參數(shù)必須是
          函數(shù)聲明中的最后一個(gè)參數(shù)。假設(shè)我們要寫一個(gè)簡(jiǎn)單的方法打印一些對(duì)象,
          util.write(obj1);
          util.write(obj1,obj2);
          util.write(obj1,obj2,obj3);
            在JDK1.5之前,我們可以用重載來(lái)實(shí)現(xiàn),但是這樣就需要寫很多的重載函數(shù),顯得
          不是很有效。如果使用可變參數(shù)的話我們只需要一個(gè)函數(shù)就行了
          public void write(Object... objs) {
             for (Object obj: objs)
                System.out.println(obj);
          }
            在引入可變參數(shù)以后,Java的反射包也更加方便使用了。對(duì)于
          c.getMethod("test", new Object[0]).invoke(c.newInstance(), new 
          Object[0])),現(xiàn)在我們可以這樣寫了
          c.getMethod("test").invoke(c.newInstance()),這樣的代碼比原來(lái)清楚了很多。 
            6.靜態(tài)導(dǎo)入(Static Imports)
            要使用用靜態(tài)成員(方法和變量)我們必須給出提供這個(gè)方法的類。使用靜態(tài)導(dǎo)入
          可以使被導(dǎo)入類的所有靜態(tài)變量和靜態(tài)方法在當(dāng)前類直接可見,使用這些靜態(tài)成員無(wú)需
          再給出他們的類名。
          import static java.lang.Math.*;
          …….
          r = sin(PI * 2); //無(wú)需再寫r = Math.sin(Math.PI);
            不過(guò),過(guò)度使用這個(gè)特性也會(huì)一定程度上降低代碼地可讀性。
          元數(shù)據(jù)
          J2SE 1.5 中的元數(shù)據(jù)特性提供這樣的能力,即向 Java 類、接口、方法和字段關(guān)聯(lián)附加的數(shù)據(jù)。這些附加的數(shù)據(jù)或者注釋,可以被 javac 編譯器或其他工具讀取,并且根據(jù)配置不同,可以被保存在類文件中,也可以在運(yùn)行時(shí)使用 Java 反射 API 被發(fā)現(xiàn)。
          向 Java 平臺(tái)增加元數(shù)據(jù)的一個(gè)主要原因是,使得開發(fā)工具和運(yùn)行工具有一個(gè)通用的基礎(chǔ)結(jié)構(gòu),以減少開發(fā)和部署所需的成本。工具可以使用元數(shù)據(jù)信息生成附加的源代碼,或者在調(diào)試時(shí)提供附加信息。
          下面的例子用元數(shù)據(jù)工具創(chuàng)建了一個(gè)調(diào)試元數(shù)據(jù)注釋,這些元數(shù)據(jù)注釋然后又簡(jiǎn)單地在運(yùn)行時(shí)顯示出來(lái)。可以想像,大部分的元數(shù)據(jù)標(biāo)簽形成一個(gè)標(biāo)準(zhǔn),即一個(gè)良好規(guī)范的集合。
          import java.lang.annotation.*;
          import java.lang.reflect.*;

          @Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @interface debug {
          boolean devbuild() default false;
          int counter();
          }

          public class MetaTest {
          final boolean production=true;
          @debug(devbuild=production,counter=1) public void testMethod() {
          }


          public static void main(String[] args) {

          MetaTest mt = new MetaTest();
          try {
          Annotation[] a = mt.getClass().getMethod("testMethod").getAnnotations();
          for (int i=0; i<a.length ; i++) {
          System.out.println("a["+i+"]="+a+" ");
          }
          } catch(NoSuchMethodException e) {
          System.out.println(e);
          }
          }
          }

          利用一個(gè)元數(shù)據(jù)處理工具,許多重復(fù)的代碼編寫步驟可以減少成一個(gè)簡(jiǎn)練的元數(shù)據(jù)標(biāo)簽。例如,訪問(wèn)某個(gè) JAX-RPC 服務(wù)實(shí)現(xiàn)時(shí)所需的遠(yuǎn)程接口可以實(shí)現(xiàn)為:
          原來(lái)(J2SE 1.5 以前版本):
          public interface PingIF extends Remote {
          public void ping() throws RemoteException;
          }
          public class Ping implements PingIF {
          public void ping() {
          }
          }
           

          現(xiàn)在:
          public class Ping {
          public @remote void ping() {
          }
          }
          二、元數(shù)據(jù)(注解)
            這是JDK5.0學(xué)XDoclt的,有了注解,以后我們可以不必寫接口,EJB寫起來(lái)會(huì)方便很多。EJB3.0要精簡(jiǎn)寫法,注解要占一些功勞。
            介紹一個(gè)常用的注解:@Override,示例如下:
          public class Test extends ATest{

          @Override
              public void test() {
              }
          }
           在方法前加了這個(gè)注解,就限定死了Test的這個(gè)方法一定要是覆蓋自ATest的方法test,否則就會(huì)報(bào)錯(cuò)。比如你不心把方法test()寫成了tesd(),編譯時(shí)就會(huì)報(bào)錯(cuò)。另一個(gè)要注意的是@Override用于定義覆蓋接口的方法,也就是說(shuō)ATest必須是一個(gè)抽象類、普通類,但不能是接口。
             另一個(gè)常見到的注解是@Deprecated,表明該項(xiàng)(類、字段、方法)不再被推薦使用。不過(guò)我們自己一般很少用到這個(gè)注解。
            好了,注解只講這兩個(gè)吧,也不必了解太多,知道個(gè)概念,以后用到的時(shí)候再說(shuō)吧。關(guān)于注解,建議看看XDoclt,這是一個(gè)開源小工具,在項(xiàng)目開發(fā)中非常好用。
          我喜愛的Java 5.0的五個(gè)特性
          作者:David Flanagan, Java in a Nutshell, 第5版的作者

          版權(quán)聲明:可以任意轉(zhuǎn)載,轉(zhuǎn)載時(shí)請(qǐng)務(wù)必以超鏈接形式標(biāo)明文章原始出處和作者信息及本聲明
          作者:
          David Flanagan;xml1123
          原文地址:
          http://www.onjava.com/pub/a/onjava/2005/04/20/javaIAN5.html
          中文地址:
          http://www.matrix.org.cn/resource/article/43/43830_Java5.html
          關(guān)鍵詞: Java5

          至今,毫無(wú)疑問(wèn)你已經(jīng)看過(guò)不止一篇網(wǎng)上文章列舉了Java5.0的偉大的語(yǔ)言新特性:泛型,標(biāo)注,枚舉類型,自動(dòng)裝箱,可變參數(shù), for/in循環(huán),甚至靜態(tài)引入。我也認(rèn)為這些是偉大的特性,但是,你已經(jīng)讀過(guò)他們了。因此,在此我將集中于你可能沒(méi)有聽說(shuō)過(guò)的Java5.0的新API特性。

          那么,在下面,是我喜歡的Java5.0的五個(gè)新API特性。我已經(jīng)在《果殼中的Java》(《Java in a nut shell》)第五版的第五章中介紹過(guò)他們。并且我也在我的網(wǎng)站中記錄了其中的一些。那些看完本文后的細(xì)心的讀者會(huì)發(fā)現(xiàn)額外的獎(jiǎng)勵(lì)—第六個(gè)特性:很少有人知道的Java5.0支持的新語(yǔ)言語(yǔ)法,當(dāng)然使用者就更少了。我非常喜歡它,因?yàn)樗苄庐悺?br>
          Callable 和 Future 接口

          我喜歡的第一個(gè)特性發(fā)掘自新的java.util.concurrent包。如它的名字暗示的,這是個(gè)并行編程工具包。在此有很多要探索的,而我要提的第一喜歡的特性是TimeUnit枚舉類型。TimeUnit讓我感興趣的是它包含有用的時(shí)間相關(guān)工具--你通過(guò)一個(gè)枚舉常量來(lái)調(diào)用它們,該常量代表度量時(shí)間的單位。例如:
          TimeUnit.MILLISECONDS.sleep(200);

          然而,TimeUnit并不是最值得夸獎(jiǎng)的。java.util.concurrent最強(qiáng)大的特性之一是它的任務(wù)-執(zhí)行/線程-池結(jié)構(gòu)。ExecutorService接口提供了執(zhí)行任務(wù)的能力。Executors類定義了工廠方法用于獲取使用線程池的ExecutorService的實(shí)現(xiàn)。這是強(qiáng)大的要素。

          我所喜歡的任務(wù)-執(zhí)行框架的部分是它如何表現(xiàn)任務(wù)以及執(zhí)行它的結(jié)果:Callable和Future接口。我們都熟悉用于定義線程的Runnable接口和它的run()方法。Callable像Runnable,但它的方法叫做call(),并且這個(gè)方法可以返回一個(gè)結(jié)果或者拋出一個(gè)異常,而這兩點(diǎn)是Runnable.run()做不到的。

          Callable是一個(gè)泛型,并且它的結(jié)果已經(jīng)參數(shù)化。例如,一個(gè)計(jì)算BigInteger的任務(wù),是Callable<BigInteger>,并且它的方法call()被聲明為返回BigInteger。下面是僅有三行代碼的Callable接口:

          public interface Callable<V> {
                V call() throws Exception;
            }


          當(dāng)我想要異步執(zhí)行一個(gè)Callable任務(wù),我將它傳遞給ExecutorService的submit()方法。submit()的返回值—這也是我喜歡的部分—是一個(gè)Future對(duì)象:本質(zhì)上是一個(gè)對(duì)將來(lái)某時(shí)刻的結(jié)果的“借條”。如果我準(zhǔn)備使用我的任務(wù)的結(jié)果,我簡(jiǎn)單的調(diào)用Future對(duì)象的get()方法即可。如果任務(wù)的執(zhí)行已完成,那么get()立刻返回結(jié)果。否則,它將阻塞直到結(jié)果可用。如果Callable拋出異常,那么get()方法將該異常包裝為ExecutionException并且拋出它。Future還有方法用來(lái)對(duì)任務(wù)的執(zhí)行進(jìn)行取消和查詢狀態(tài),但是你必須自己查找它們(這些方法)。Future也用了泛型,并且結(jié)果的類型也參數(shù)化了。因此如果我submit()一個(gè)Callable<BigInteger>來(lái)執(zhí)行,我將獲得一個(gè)Future< BigInteger >。

          下面是一個(gè)簡(jiǎn)短的例子:

          /**
          * 這是一個(gè)用來(lái)計(jì)算大素?cái)?shù)的Callable。
          */
          public class PrimeSearch implements Callable<BigInteger>
          {
              static Random prng = new SecureRandom();
              int n;
              public PrimeSearch(int bitsize) { n = bitsize; }
              public BigInteger call() {
                  return BigInteger.probablePrime(n, prng);
              }
          }

          // 嘗試同時(shí)計(jì)算兩個(gè)素?cái)?shù)
          ExecutorService pool = Executors.newFixedThreadPool(2);
          Future<BigInteger> p = pool.submit(new PrimeSearch(512));
          Future<BigInteger> q = pool.submit(new PrimeSearch(512));

          // 將兩個(gè)素?cái)?shù)相乘來(lái)得到一個(gè)合數(shù)
          BigInteger product = p.get().multiply(q.get());



          可變參數(shù)和自動(dòng)裝箱

          我說(shuō)過(guò)我不想談?wù)揓ava5.0的新語(yǔ)言特性,我不會(huì),但是我確實(shí)關(guān)注由于可變參數(shù)和自動(dòng)裝箱才變?yōu)榭赡艿模ɑ蛘弑辉鰪?qiáng)的舊API)新的API。

          首先,當(dāng)然,是Java5.0的printf風(fēng)格的文本格式化能力,通過(guò)java.util.Formatter類和類似String.format()的工具方法。這類文本格式化是最常被引用來(lái)支持語(yǔ)言的增加的可變參數(shù)和自動(dòng)裝箱的那種用例。考慮這個(gè):

          String s = String.format("%s:%d: %s%n", filename,
                                     lineNumber,
                                       exception.getMessage());


          關(guān)于這段代碼沒(méi)有什么特別值得注意的東西。我將它列在這是為了說(shuō)明因?yàn)榭勺儏?shù)和自動(dòng)裝箱所以比下面的例子顯得簡(jiǎn)單:

          String s = String.format("%s:%d: %s%n", new Object[] {
                                     filename,
                                     new Integer(lineNumber),
                                       exception.getMessage()});

          一、C風(fēng)格格式化輸出
          在JDK5.0后,我們這樣寫代碼:
              public static void main(String[] args) {
                  int x = 10;
                  int y = 20;
                  int sum = x + y;
                  System.out.printf("%d + %d = %d", x, y, sum);
              }

          可變參數(shù)和自動(dòng)裝箱還對(duì)java.lang.reflect API有一個(gè)實(shí)質(zhì)性的影響。那就是當(dāng)查找和調(diào)用方法時(shí)不再需要類和對(duì)象數(shù)組:

          Method m = c.getMethod("put", Object.class,Object.class);
            m.invoke(map, "key", "value");


          如果我必須選擇一個(gè)最喜歡的可變參數(shù)方法,那么,將是java.util.Arrays.asList()。這個(gè)方法真是個(gè)用于創(chuàng)建不變的對(duì)象列表的方便的工廠方法。它接受任何數(shù)量的類型T的參數(shù)并且將它們作為L(zhǎng)ist<T>返回:

          List<Integer> smallPrimes =
               Arrays.asList(2, 3, 5, 7, 11, 13, 17, 19);


          能力

          我們?cè)谏厦嬲務(wù)摿薘unnable和Callable,并且你毫無(wú)疑問(wèn)已經(jīng)聽說(shuō)過(guò)重要的Comparable, Serializable,和Cloneable接口。Java5.0新增加了五個(gè)重要的能力接口。第一個(gè),當(dāng)然,是java.lang.Iterable。你或許知道Java5.0新的for/in循環(huán)可以迭代數(shù)組和集合。你可能不知道它能夠?qū)θ魏螌?shí)現(xiàn)了可迭代(Iterable)接口的對(duì)象工作。因此,如果你想讓一個(gè)不是集合的數(shù)據(jù)結(jié)構(gòu)可以簡(jiǎn)單地迭代,只需實(shí)現(xiàn)Iterable接口。你要做的就是增加一個(gè)返回java.util.Iterator 的iterator()方法。當(dāng)然,寫這個(gè)迭代器(Iterator)可能不是那么簡(jiǎn)單的。

          下面的代碼是一個(gè)實(shí)現(xiàn)了Iterable<String>(是的,Iterable是泛型的)的文本文件類,因而允許文本文件可以用for/in循環(huán)逐行的迭代。你可以用類似下面的代碼使用它:

          TextFile textfile = new TextFile(new File(f), "UTF-8");
            int lineNumber = 0;
            for(String line : textfile)
                System.out.printf("%6d: %s%n", ++lineNumber, line);


          下面是TextFile的代碼。注意,迭代器不嘗試檢測(cè)對(duì)底層文件的并發(fā)的修改。如果你想自己做,看一看

          java.nio.channels.FileLock。
          import java.io.*;
          import java.util.Iterator;

          public class TextFile implements Iterable<String> {
              File f;
              String charsetName;

              public TextFile(File f, String charsetName)
                  throws IOException
              {
                  this.f = f;
                  this.charsetName = charsetName;

                  if (!f.exists())
                      throw new FileNotFoundException(f.getPath());
                  if (!f.canRead())
                      throw new IOException("Can't read: " +
                                            f.getPath());
              }

              public Iterator<String> iterator() {
                  try {
                      return new TextFileIterator(f, charsetName);
                  }
                  catch(IOException e) {
                      throw new IllegalArgumentException(e);
                  }
              }


              static class TextFileIterator
                  implements Iterator<String>
              {
                  BufferedReader in;
                  String nextline;
                  boolean closed = false;

                  public TextFileIterator(File f, String charsetName)
                      throws IOException
                  {
                      InputStream fis = new FileInputStream(f);
                      Reader isr =
                          new InputStreamReader(fis, charsetName);
                      in = new BufferedReader(isr);
                      getNextLine();
                  }

                  public boolean hasNext() {
                      return nextline != null;
                  }

                  public String next() {
                      String returnValue = nextline;
                      getNextLine();
                      return returnValue;
                  }

                  public void remove() {
                      throw new UnsupportedOperationException();
                  }

                  void getNextLine() {
                      if (!closed) {
                          try { nextline = in.readLine(); }
                          catch(IOException e) {
                              throw new IllegalArgumentException(e);
                          }
                          if (nextline == null) {
                              try { in.close(); }
                              catch(IOException ignored) {}
                              closed = true;
                          }
                      }
                  }
              }
          }


          Iterable是到目前為止最重要的新能力接口,但是其它的也是非常的漂亮。接下來(lái),我們碰到j(luò)ava.lang.Appendable。一個(gè)Appendable對(duì)象可以追加字符或字符序列(或者一個(gè)字符序列的子序列)。實(shí)現(xiàn)者包括StringBuffer和StringBuilder(如果你還沒(méi)有聽說(shuō)過(guò)它,一定要看一看),Writer(及其子類),PrintStream,還有java.nio.CharBuffer。將可追加性從這些類中分離出來(lái)成為Appendable接口,使得新的java.util.Formatter類更強(qiáng)大:它能將文本格式化為任何可追加的對(duì)象,包括你自己的實(shí)現(xiàn)。(練習(xí)留給讀者:你能否將上面的TextFile類變得既可迭代又可追加么?)。


          java.lang.Readable接口和Appendable相反:一個(gè)可讀對(duì)象可以將字符傳輸給給定的CharBuffer。java.io.Reader和它的全部子類都是可讀的(當(dāng)然了),CharBuffer本身也一樣。就像Appendable是為了java.util.Formatter的利益而創(chuàng)造,Readable是為了java.util.Scanner的利益而創(chuàng)造。(Java5.0增加了Scanner,連同F(xiàn)ormatter。這是Java對(duì)C的scanf()函數(shù)的適應(yīng),但是它(Scanner)不像Formatter之對(duì)應(yīng)于printf()的關(guān)系那樣密切。)

          我想討論的最后兩個(gè)能力接口是java.io.Closeable和java.io.Flushable。如它們的名字暗示的,它們趨向于被任何類實(shí)現(xiàn),通過(guò)一個(gè)close()或者flush()方法。Closeable被所有的輸入和輸出流類,RandomAccessFile和Formatter實(shí)現(xiàn)。Flushable被輸出流類和Formatter實(shí)現(xiàn)。這些接口也是為了Formatter類的利益而定義。注意,Appendable對(duì)象(像StringBuilder)不總是可關(guān)閉或者可沖刷(flushable)。通過(guò)將可關(guān)閉性和可沖刷性分解出來(lái)成為這些接口,F(xiàn)ormatter的close()和flush()方法能夠決定它們操作的Appendable對(duì)象是否需要被關(guān)閉或被沖刷。(Java5.0還增加了第六個(gè)能力接口,并且它也是有關(guān)Formatter類的。那些想要控制它們的實(shí)例怎樣被格式化的類可以實(shí)現(xiàn)java.util.Formattable接口。然而這個(gè)接口的API是難用的,我不想談?wù)撍#?br>
          @Override

          毫無(wú)疑問(wèn),你已經(jīng)聽說(shuō)過(guò)能用元數(shù)據(jù)標(biāo)注Java5.0的類型和方法。但是你可能不熟悉增加到j(luò)ava.lang的標(biāo)準(zhǔn)標(biāo)注類型。我喜歡的第四個(gè)特性就是java.lang.Override標(biāo)注。當(dāng)你寫一個(gè)方法準(zhǔn)備覆蓋另一個(gè)的方法時(shí),用@Override來(lái)標(biāo)注它,這樣編譯器會(huì)進(jìn)行檢查來(lái)確保你確實(shí),實(shí)際上,覆蓋了你想覆蓋的方法。

          如果你拼寫錯(cuò)了方法名字或者弄錯(cuò)了方法參數(shù),那么你實(shí)際上并沒(méi)有覆蓋那個(gè)你認(rèn)為你覆蓋了的方法。這樣就造成了一個(gè)如果不用@Override很難捕捉的臭蟲。我所以知道是因?yàn)槲业年P(guān)于Java1.4的新API特性的文章就講到了這個(gè)臭蟲,并且這個(gè)錯(cuò)誤至少有一年一直沒(méi)被檢測(cè)到(至少?zèng)]有被報(bào)告)。在那篇文章中,你可以在第一頁(yè)結(jié)尾看到我犯的錯(cuò)誤。那篇文章現(xiàn)在包含一個(gè)鏈接到我的博客入口,在那里我改正了這個(gè)臭蟲并且在代碼中增加了@Override聲明。

          MatchResult
          我喜歡的Java5.0的最后一個(gè)特性是java.util.regex.MatchResult。對(duì)于用于正則表達(dá)式的模式/匹配API我從來(lái)沒(méi)有真正非常滿意。Java5.0增加的MatchResult在讓我大大地更加滿意。當(dāng)使用一個(gè)不太平凡的模式(Pattern),每次調(diào)用匹配者(Matcher)的find()方法會(huì)生成許多狀態(tài):開始位置,結(jié)束位置,匹配的文本,同時(shí)還有模式的開始,結(jié)束,每個(gè)子表達(dá)式的文本。在Java5.0以前,你只能從Matcher獲取它們,通過(guò)在調(diào)用find()后再調(diào)用start(),end(),還有g(shù)roup(),如果需要的話。

          然而,到了Java5.0,你可以只調(diào)用toMatchResult()來(lái)獲取MatchResult對(duì)象再獲取全部的狀態(tài),MatchResult對(duì)象可以保存并且可以以后再檢查。MatchResult像Matcher一樣有start(),end(),以及group()方法,并且,實(shí)際上,Matcher現(xiàn)在實(shí)現(xiàn)了MatchResult。
          這里是一個(gè)有用的返回MatchResult的方法:

          public static List<MatchResult> findAll(Pattern pattern,
                                                  CharSequence text)  {
              List<MatchResult> results =
                  new ArrayList<MatchResult>();
              Matcher m = pattern.matcher(text);
              while(m.find()) results.add(m.toMatchResult());
              return results;
          }


          還有使用這個(gè)方法的代碼:

          List<MatchResult> results = findAll(pattern, text);
          for(MatchResult r : results) {
              System.out.printf("Found '%s' at (%d,%d)%n",
                                r.group(), r.start(), r.end());
          }



          十六進(jìn)制浮點(diǎn)數(shù)字面值

          我承諾談?wù)揓ava5.0的最晦澀的新語(yǔ)言特性。這就是:十六進(jìn)制格式的浮點(diǎn)常量!這里是奇異的詳情:一個(gè)十六進(jìn)制符號(hào)的浮點(diǎn)常量以0X或者0x開頭。隨后的十六進(jìn)制數(shù)字形成了數(shù)的基數(shù)。關(guān)鍵是這些數(shù)字可以包含一個(gè)小數(shù)點(diǎn)(一個(gè)十六進(jìn)制小數(shù)點(diǎn)?)。在基數(shù)后面是指數(shù),是必需的。十六進(jìn)制浮點(diǎn)常量使用p或者P而不是e或者E來(lái)引入指數(shù)。(想一下“冪”來(lái)幫助記憶)。P或者P后面是指數(shù),必須是一個(gè)十進(jìn)制數(shù),而不是十六進(jìn)制數(shù)。而且這是個(gè)以二為根的指數(shù),而不是以十為根。那就是,表示基數(shù)要乘以的2的冪。最后,整個(gè)常量可以跟隨一個(gè)f或者F來(lái)表示一個(gè)浮點(diǎn)常量,或者一個(gè)d或者D表示一個(gè)雙精度常量,就像一個(gè)十進(jìn)制浮點(diǎn)數(shù)一樣。
          下面是一些例子:

          double x = 0XaP0;    // 10 * 2^0 = 10.0
            double y = 0XfP2D;   // 15 * 2^2 = 60.0
            float z  = 0Xf.aP1F; // (15 + 10/16ths) * 2^1 = 31.25f
            // 用十進(jìn)制來(lái)打印
            System.out.printf("%f %f %f%n", x, y, z);
            // 用十六進(jìn)制來(lái)打印
            System.out.printf("%a %a %a%n", x, y, z);


          為什么Sun要對(duì)語(yǔ)言做這些?5.0的發(fā)行說(shuō)明說(shuō):
          為了允許特定浮點(diǎn)值實(shí)現(xiàn)精確及可預(yù)見的規(guī)范,十六進(jìn)制符號(hào)可用于Float和Double的浮點(diǎn)字面值和字符串到浮點(diǎn)數(shù)的轉(zhuǎn)換方法中。

          這點(diǎn)是合理的。十進(jìn)制小數(shù)像0.1是不能精確地用浮點(diǎn)格式表示的,并且如果你真的需要確切知道在一個(gè)浮點(diǎn)或者雙精度值中比特位是怎么設(shè)的,那么你真的想要一個(gè)十六進(jìn)制字面值。例如,F(xiàn)loat.MAX_VALUE的Javadoc指出最大的浮點(diǎn)值是0x1.fffffeP+127f。

          如果你知道并且喜歡IEEE-754浮點(diǎn)標(biāo)準(zhǔn),那么十六進(jìn)制浮點(diǎn)字段值或許是你喜歡的一個(gè)特性。我只是認(rèn)為他們有趣。
          一 從xml中裝載屬性
           
          格式:

          <properties>
          <comment>Hi</comment>
          <entry key="id">1</entry>
          <entry key="name">rocie</entry>
          <entry key="email">rocie@sina.com</entry>
          </properties>

           
           
           
          通過(guò)以下方法加載:

          Properties prop = new Properties();
          FileInputStream fis =  new FileInputStream("d:/jdk5/properties/test.xml");
          prop.loadFromXML(fis);
          prop.list(System.out);
          System.out.println("Name: " + prop.getProperty("name"));

           
           
           
          將xml文件放在WEB-INF/classes/目錄下,可以防止對(duì)路徑的硬編碼

          InputStream is = PropertiesTest.class.getClassLoader().getResourceAsStream("rocie.xml");
          Properties ps = new Properties();
          ps.loadFromXML(is);
          System.out.println("name:"+ps.getProperty("name"));        

           
           
           
          通過(guò)以下方法保存:

          Properties prop = new Properties();
          prop.setProperty("id", "2");
          prop.setProperty("name", "彭大雙");
          prop.setProperty("email", "pds@dotraining.com");
          FileOutputStream fos = new FileOutputStream("d:/jdk5/properties/pds.xml");
          prop.storeToXML(fos, "彭大雙","gbk");
          fos.close();

           
           
           
          xml文件細(xì)節(jié):

          <?xml version="1.0" encoding="UTF-8"?>
          <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
          <properties>
          <comment>Hi</comment>
          <entry key="id">1</entry>
          <entry key="name">rocie</entry>
          <entry key="email">rocie@sina.com</entry>
          </properties>

           
           
           
          DTD文件:

          <?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>

          注:?表示0或1;*表示0至無(wú)限;+表示至少一個(gè)
           
           
           
          二 并發(fā)集合
          問(wèn)題:ConcurrentModificationExceptionfail-fast
           
           
          當(dāng)遍歷一個(gè)Iterator時(shí),如果該Iterator對(duì)應(yīng)的List里的元素發(fā)生改變,則拋出這個(gè)異常。
          解決方法:java.util.concurrent
           
           
          用CopyOnWriteArrayList代替原來(lái)的ArrayList
          copy-on-write:這意味著如果有大量的讀(即 get() ) 和迭代,不必同步操作以照顧偶爾的寫(即 add() )調(diào)用。對(duì)于新的 CopyOnWriteArrayList 和 CopyOnWriteArraySet 類,所有可變的(mutable)操作都首先取得后臺(tái)數(shù)組的副本,對(duì)副本進(jìn)行更改,然后替換副本。這種做法保證了在遍歷自身更改的集合時(shí),永遠(yuǎn)不會(huì)拋出 ConcurrentModificationException 。遍歷集合會(huì)用原來(lái)的集合完成,而在以后的操作中使用更新后的集合。
           
           
           
          用 for/in 在 Java 5.0 中增強(qiáng)循環(huán)

          public static List<Integer> list = new ArrayList<Integer>();
                
                 public static int[] is = new int[]{1,2,3,4,65,456};
                
                 static
                 {           
                        for(int i=0;i<100;i++)
                               list.add(i);             
                 }
                
                 public static void main(String args[])
                 {
                        for(Integer i:list)
                               System.out.println(i);    
                        System.out.println("-------other for each--------");
                        for(int i:is)
                               System.out.println(i);
                 }

          枚舉類型 enum

          public class EnumTest {
                 private Color color;
                
                 public static enum Color {red,yellow,blue,green};    
                
                 public Color getColor() {
                        return color;
                 }
           
           
           
                 public void setColor(Color color) {
                        this.color = color;
                 }
           
           
           
                 public static void main(String args[])
                 {
                        for(Color c:Color.values())
                        {
                               System.out.println("name:"+c.name()+"ordinal:"+c.ordinal());
                        }    
                        EnumTest et = new EnumTest();
                        et.setColor(Color.red);
                        Color c = et.getColor();
                        switch(c)
                        {
                        case red: System.out.println("red:"+c.name()+c.ordinal());
                                             break;
                        case yellow: System.out.println("yellow"+c.name()+c.ordinal());
                                             break;
                        default : System.out.println("over");
                        }
                       
                 }
          }
           
           

           
          并發(fā)實(shí)用程序
          并發(fā)實(shí)用程序庫(kù)由 Doug Lea 定義在 JSR-166 中,是 J2SE 1.5 平臺(tái)中流行的并發(fā)軟件包的一個(gè)特殊版本。它提供強(qiáng)大的、高級(jí)別的線程構(gòu)造,包括 executors(這是一個(gè)線程任務(wù)框架)、線程安全隊(duì)列、Timers、鎖(包括原子鎖)和其他同步原語(yǔ)。
          著名的旗語(yǔ)(semaphore)是這樣一個(gè)鎖。旗語(yǔ)與現(xiàn)在使用的 wait 的使用方式相同,用于限制對(duì)一塊代碼的訪問(wèn)。旗語(yǔ)更加靈活,并且也允許許多并發(fā)的線程訪問(wèn),同時(shí)允許您在獲得一個(gè)鎖之前對(duì)它進(jìn)行測(cè)試。下面的例子使用剛好一個(gè)旗語(yǔ),也叫做二進(jìn)制旗語(yǔ)。更多信息請(qǐng)參見 java.util.concurrent 軟件包。
          final private Semaphore s= new Semaphore(1, true);
          s.acquireUninterruptibly(); //for non-blocking version use s.acquire()

          balance=balance+10; //protected value
          s.release(); //return semaphore token

          rmic —— rmi 編譯器
          您不再需要使用 rmic —— rmi 編譯器工具——來(lái)生成最遠(yuǎn)程的接口存根。動(dòng)態(tài)代理的引入意味著通常由存根提供的信息可以在運(yùn)行時(shí)被發(fā)現(xiàn)。更多信息請(qǐng)參見 RMI 版本說(shuō)明。
          可擴(kuò)展性和性能
          1.5 版本承諾在可擴(kuò)展性和性能方面的改進(jìn),新的重點(diǎn)在于啟動(dòng)時(shí)間和內(nèi)存占用,使它更加易于以最大的速度部署應(yīng)用程序。
          最重大的一個(gè)更新是引入了 Hotspot JVM 中的類數(shù)據(jù)共享。該技術(shù)不僅在多個(gè)正在運(yùn)行的 JVM 之間共享只讀數(shù)據(jù),而且改進(jìn)了啟動(dòng)時(shí)間,因?yàn)楹诵牡?JVM 類都是預(yù)先打包的。
          性能工效是 J2SE 1.5 中的一個(gè)新特性,這意味著如果您一直使用的是以前版本中專門的 JVM 運(yùn)行時(shí)選項(xiàng), 那么可能值得不用選項(xiàng)或者用很少的選項(xiàng)重新驗(yàn)證您的性能。
          監(jiān)控和可管理性
          監(jiān)控和可管理性是 Java 平臺(tái)中的 RAS (Reliability, Availability, Serviceability,即可*性、可用性、可服務(wù)性) 的一個(gè)關(guān)鍵組件。
          JVM Monitoring & Management API (JSR-174) 指定一組全面的可以從正在運(yùn)行的 JVM 進(jìn)行監(jiān)控的 JVM internals。 該信息可通過(guò) JMX (JSR-003) MBeans 訪問(wèn)到,也可以使用 JMX 遠(yuǎn)程接口 (JSR-160) 和行業(yè)標(biāo)準(zhǔn) SNMP 工具而遠(yuǎn)程訪問(wèn)得到。
          最有用的一個(gè)特性是一個(gè)低內(nèi)存檢測(cè)程序。當(dāng)超過(guò)閥值時(shí),JMX MBeans 可以通知已注冊(cè)的偵聽程序。更多信息請(qǐng)參見 javax.management 和 java.lang.management。
          為了了解新的 API 是多么容易使用,下面報(bào)告了 Hotspot JVM 中內(nèi)存堆的詳細(xì)使用情況。
          import java.lang.management.*;
          import java.util.*;
          import javax.management.*;
          public class MemTest {
          public static void main(String args[]) {
          List pools =ManagementFactory.getMemoryPoolMBeans();
          for(ListIterator i = pools.listIterator(); i.hasNext();) {
          MemoryPoolMBean p = (MemoryPoolMBean) i.next();
          System.out.println("Memory type="+p.getType()+" Memory usage="+p.getUsage());
          }
          }
          }

          新的 JVM profiling API (JSR-163)
          該版本還包含一個(gè)更強(qiáng)大的本機(jī) profiling API,叫做 JVMTI。該 API 已經(jīng)在 JSR 163 中指定了,并由對(duì)改善的 profiling 接口的需求所推動(dòng)。但是,JVMTI 除了具有 profiling 功能之外,還想要涵蓋全范圍的本機(jī)內(nèi)部過(guò)程工具訪問(wèn),包括監(jiān)控工具、調(diào)試工具以及潛在的各種各樣的其他代碼分析工具。
          該實(shí)現(xiàn)包含一個(gè)用于字節(jié)碼裝置(instrumentation)——Java 編程語(yǔ)言裝置服務(wù)(Java Programming Language Instrumentation Services,JPLIS)的機(jī)制。這使得分析工具只在需要的地方添加額外的配置信息(profiling)。該技術(shù)的優(yōu)點(diǎn)是,它允許更加集中的分析,并且限制了正在運(yùn)行的 JVM 上的 profiling 工具的引用。該裝置甚至可以在運(yùn)行時(shí)和類加載時(shí)動(dòng)態(tài)地生成,并且可以作為類文件預(yù)先處理。
          下面這個(gè)例子創(chuàng)建了一個(gè)裝置鉤(instrumentation hook),它可以從磁盤加載類文件的一個(gè)已修改的版本。要運(yùn)行該測(cè)試,可利用 java -javaagent:myBCI BCITest 啟動(dòng) JRE。

          //File myBCI.java
          import java.lang.instrument.Instrumentation;

          public class myBCI {
          private static Instrumentation instCopy;

          public static void premain(String options, Instrumentation inst) {
          instCopy = inst;
          }
          public static Instrumentation getInstrumentation() {
          return instCopy;
          }
          }

          //File BCITest.java

          import java.nio.*;
          import java.io.*;
          import java.nio.channels.*;
          import java.lang.instrument.*;

          public class BCITest {
          public static void main (String[] args) {
          try {
          OriginalClass mc = new OriginalClass();
          mc.message();

          FileChannel fc=new FileInputStream(new File("modified"+File.separator+"OriginalClass.class")).getChannel();
          ByteBuffer buf = fc.map(FileChannel.MapMode.READ_ONLY, 0, (int)fc.size());
          byte[] classBuffer = new byte[buf.capacity()];
          buf.get(classBuffer, 0, classBuffer.length);
          myBCI.getInstrumentation().redefineClasses(new ClassDefinition[] {new ClassDefinition(mc.getClass(), classBuffer)});
          mc.message();
          }catch (Exception e){}
          }
          }

          //OriginalClass.java
          //Compile in current directory
          //Copy source to modified directory,change message and recompile

          public class OriginalClass {
          public void message() {
          System.out.println("OriginalClass");
          }
          }



          改進(jìn)的診斷能力
          如果沒(méi)有控制臺(tái)窗口可用,生成的 Stack 跟蹤就很笨拙。兩個(gè)新的 API —— getStackTrace 和 Thread.getAllStackTraces —— 以程序的方式提供該信息。
          StackTraceElement e[]=Thread.currentThread().getStackTrace();
          for (int i=0; i <e.length; i++) {
          System.out.println(e);
          }
          System.out.println("\n"+Thread.getAllStackTraces());

          Hotspot JVM 包含一個(gè)致命的錯(cuò)誤處理程序(error hander),如果 JVM 異常中斷,它可以運(yùn)行用戶提供的腳本。使用 Hotspot JVM 可服務(wù)性代理連接器,調(diào)試工具也可以連接到一個(gè)掛起的 JVM 或者核心文件。
          -XX:OnError="command"
          -XX:OnError="pmap %p"
          -XX:OnError="gdb %p"
          optional %p used as process id

          桌面客戶端
          Java 桌面客戶端保留有 Java 平臺(tái)的一個(gè)關(guān)鍵組件,并且這一點(diǎn)成了 J2SE 1.5 中許多改進(jìn)的焦點(diǎn)。
          這個(gè) Beta 版本包含啟動(dòng)時(shí)間和內(nèi)存占用方面的一些早期改進(jìn)。該版本不僅更快,并且 Swing 工具集采用了一個(gè)暫新的叫做 Ocean 的主題。
          通過(guò)建立 J2SE 1.4.2 中的更新,GTK 和 Windows XP 外觀方面有了更進(jìn)一步的改進(jìn)。

          Windows XP
          Click to Enlarge

          Linux/Redhat
          Click to Enlarge

          具有最新 OpenGL 驅(qū)動(dòng)程序并且選擇了圖形卡的 Linux 和 Solaris 用戶,可以使用下面的運(yùn)行時(shí)屬性從 Java2D 獲得本機(jī)硬件加速:
          java -Dsun.java2d.opengl=true -jar Java2D.
          Linux 版本也具有快速的 X11 Toolkit,叫做 XAWT,默認(rèn)情況下是啟用的。如果您需要與 motif 版本進(jìn)行比較,可以使用下面的系統(tǒng)屬性:
          java -Dawt.toolkit=sun.awt.motif.MToolkit -jar Notepad.jar
          (X11 Toolkit 叫做 sun.awt.X11.XToolkit)
          X11 Toolkit 也使用 XDnD 協(xié)議,所以您可以在 Java 和其他應(yīng)用(比如 StarOffice 或 Mozilla)之間拖放簡(jiǎn)單的組件。
          其他特性
          核心 XML 支持
          J2SE 1.5 引入了核心 XML 平臺(tái)的幾個(gè)修訂,包括 XML 1.1 和 Namespace、XML Schema、SAX 2.0.1、XSLT 和快速 XLSTC 編譯器,以及最后的 DOM 第 3 層支持。
          除了支持核心 XML 之外,未來(lái)版本的 Java Web Services Developer Pack 將交付最新的 Web 服務(wù)標(biāo)準(zhǔn):JAX-RPC & SAAJ (WSDL/SOAP)、JAXB、XML Encryption and Digital Signature,以及用于注冊(cè)的 JAXR。
          輔助字符支持
          32 位的輔助字符支持作為傳輸?shù)?Unicode 4.0 支持的一部分,已經(jīng)慎重地添加到該平臺(tái)。輔助字符被編碼為一對(duì)特殊的 UTF16 值,以生成一個(gè)不同的字符或者碼點(diǎn)(codepoint)。一個(gè)代理對(duì)(surrogate pair)是一個(gè)高 UTF16 值和后面的一個(gè)低 UTF16 值的組合。這些高值和低值來(lái)自一個(gè)特殊范圍的 UTF16 值。
          一般來(lái)說(shuō),當(dāng)使用 String 或者字符序列時(shí),核心 API 庫(kù)將透明地為您處理新的輔助字符。但是因?yàn)?Java "char" 仍然保留為 16 位,所以非常少的一些使用 char 作為參數(shù)的方法,現(xiàn)在有了足夠的可以接受 int 值的方法,其中 int 值可以代表新的更大的值。特別是 Character 類,具有附加的方法來(lái)檢索當(dāng)前的字符和接下來(lái)的字符,以便檢索輔助的碼點(diǎn)值,如下所示:
          String u="\uD840\uDC08";
          System.out.println(u+"+ "+u.length());
          System.out.println(Character.isHighSurrogate(u.charAt(0)));
          System.out.println((int)u.charAt(1));
          System.out.println((int)u.codePointAt(0));

          更多信息請(qǐng)參見 Character 中的 Unicode 部分。
          JDBC RowSets
          JDBC 行集支持有兩個(gè)主要的更新。CachedRowSet 包含從數(shù)據(jù)庫(kù)檢索的行的內(nèi)存中的集合。但是它們也是不連接的,這意味著以后更新可以與數(shù)據(jù)庫(kù)重新同步。
          另一個(gè)組件是 WebRowSet,它使用數(shù)據(jù)庫(kù)行通過(guò) XML 來(lái)傳輸數(shù)據(jù)。
          參考資料:
          New Language Features for Ease of Development in the Java 2 Platform, Standard Edition 1.5: http://java.sun.com/features/2003/05/bloch_qa.html
          Tiger Component JSRs
          003 Java Management Extensions (JMX) Specification http://jcp.org/en/jsr/detail?id=3
          013 Decimal Arithmetic Enhancement http://jcp.org/en/jsr/detail?id=13
          014 Add Generic Types To The Java Programming Language http://jcp.org/en/jsr/detail?id=14
          028 Java SASL Specification http://jcp.org/en/jsr/detail?id=28
          114 JDBC Rowset Implementations http://jcp.org/en/jsr/detail?id=114
          133 Java Memory Model and Thread Specification Revision http://jcp.org/en/jsr/detail?id=133
          160 Java Management Extensions (JMX) Remote API 1.0 http://jcp.org/en/jsr/detail?id=160
          163 Java Platform Profiling Architecture http://jcp.org/en/jsr/detail?id=163
          166 Concurrency Utilities http://jcp.org/en/jsr/detail?id=166
          174 Monitoring and Management Specification for the Java Virtual Machine http://jcp.org/en/jsr/detail?id=174
          175 A Metadata Facility for the Java Programming Language http://jcp.org/en/jsr/detail?id=175
          200 Network Transfer Format for Java Archives http://jcp.org/en/jsr/detail?id=200
          201 Extending the Java Programming Language with Enumerations, Autoboxing, Enhanced for Loops and Static Import http://jcp.org/en/jsr/detail?id=201
          204 Unicode Supplementary Character Support http://jcp.org/en/jsr/detail?id=204
          206 Java API for XML Processing (JAXP) 1.3 http://jcp.org/en/jsr/detail?id=206

          posted on 2007-06-22 10:49 BigMouse 閱讀(1373) 評(píng)論(0)  編輯  收藏 所屬分類: JAVA學(xué)習(xí)


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           

          導(dǎo)航

          統(tǒng)計(jì)

          留言簿(1)

          隨筆檔案(1)

          文章分類(1)

          文章檔案(1)

          友情鏈接

          最新隨筆

          搜索

          最新評(píng)論

          主站蜘蛛池模板: 南阳市| 博客| 安陆市| 芒康县| 阜康市| 建水县| 三门县| 寻甸| 富锦市| 南康市| 白银市| 阳谷县| 涪陵区| 蒲城县| 蓬安县| 曲靖市| 疏勒县| 雷山县| 辛集市| 西城区| 博乐市| 成武县| 祁门县| 额尔古纳市| 大方县| 盐源县| 南澳县| 蚌埠市| 内丘县| 怀化市| 辽宁省| 舟曲县| 花垣县| 昌平区| 桂阳县| 龙州县| 尚义县| 普陀区| 上林县| 遵义县| 喜德县|