本文中,我們將討論幾個在JDK1.5中新的語言特征,包括:
泛型(Generics)--為集合(collections)提供編譯時類型安全,無需每刻從Collections取得一個對象就進行強制轉換(cast)
增強的“for”循環(Enhanced For loop)--減少迭代器(iterator)的潛在錯誤(error-proneness)
自動置入/自動取出(Autoboxing/unboxing)--無需在基本類型(primitive types)(例如double)和包裝類型(wrapper types)(例如Double)之間人工地進行轉換。
類型安全的枚舉(Typesafeenums)--提供類型安全枚舉模式的各項好處。
靜態導入(Static import)--無需在使用其他類的靜態成員變量前綴其類名.這將使得代碼更為簡潔。
元數據(Metadata)--使編程人員避免編寫樣板化代碼(boiler plate code),并提供機會進行宣告式程式設計(declarative programming)。
讓我們詳細討論每個新特性,并看一些例子。
泛型(Generics)
泛型是JDK1.5中一個最“酷”的特征。通過引入泛型,我們將獲得編譯時類型的安全和運行時更小地拋出ClassCastExceptions的可 能。在JDK1.5中,你可以聲明一個集合將接收/返回的對象的類型。在JDK1.4中,創建雇員名字的清單(List)需要一個集合對象,像下面的語 句:
List listOfEmployeeName = new ArrayList();
在JDK1.5中,你將使用下面語句
List<String> listOfEmployeeName = new ArrayList<String>();
最“酷”的是,如果你試圖插入非string類型的值,你將在編譯時發現并且修正這類問題。沒有泛型,你會發現這樣一個bug,當你的客戶調用后會告訴你,你所編寫的程序拋出ClassCastException異常而崩潰。
另外,當你從集合中得到一個元素時你無需進行強制轉換。故原先為:
String employeeName = ((String) listOfEmployee.get(i));
而下面的語句將比上面的更加簡單:
String employeeName = listOfEmployee.get(i);
不清楚對象的類型而強制轉換對象是不合理的,并且更重要的是,它將在運行時失敗。假使用戶無意間傳入一個包含string buffers類型而非string類型的集合,那結果會怎樣呢。在Listing A中,客戶被要求傳入一個編譯器無法強制的strings類型集合。Listing B中顯示了同樣的方法使用泛型是如何實現的。
Listing A
staticbooleancheckName(Collection employeeNameList, String name) {
for (Iteratori = employeeNamList.iterator(); i.hasNext(); ) {
String s = (String) i.next();
if(s.equals(name)){
return true;
//print employee name here ......
}
}
return false;
}
Listing B
staticbooleancheckName(Collection<String> employeeNameList, String name) {
for (Iteratori = employeeNamList.iterator(); i.hasNext(); ) {
if(i.next().equals(name)){
return true;
//print employee name here ......
}
}
return false;
}
現在,通過方法簽名可以清楚知道輸入集合必須只能包含strings。如果客戶試圖傳入一個包含string buffers的集合,程序將不會編譯。同時注意,該方法不包含任何強制轉換。它只需要短短一行,一旦你習慣泛型后,它也更加清晰。
在JDK當前版本下的For循環語法如下:
void printAll(Collection c) {
for (Iteratori = c.iterator(); i.hasNext(); ) {
Employee emp = (Employee)i.next();
System.out.println(emp.getName());
}
}
現在,用增強的For語句實現相同方法:
voidprintAll(Collection c) {
for (Object o : c)
System.out.println((TimerTask)o).getName());
}
在這類For循環中,你應該將":"看成"in",所以,在該例中可以看成"for Object o in c"。你可以發現這種For循環更具可讀性。
自動置入/自動取出(Autoboxing/unboxing)
Java有基本數據類型,在這些基本數據類型周圍又有包裝類。通常,編程人員需要將一種類型轉換成另一種。看看Listing C.中的代碼片斷。
Listing C
public class Employee {
private static final Integer CHILD = new Integer(0);
public static void main(String args[]) {
//code for adding n to an Integer
int n=10;
Integer age= new Integer(30);
Integer ageAfterTenYear= new Integer(age.intValue +10);
}
}
請注意,用于計算ageAfterTenYear的內循環代碼看上去是多么雜亂。現在,在Listing D.中看看相同的程序使用autoboxing重寫后的樣子。
Listing D
public class Employee {
public static void main(String args[]) {
int n=10;
Integer age= new Integer(30);
Integer ageAfterTenYear= age +10;
}
}
有一件事值得注意的:在先前,如果你取出(unbox)Null值,它將變為0。在次代碼中,編譯器將自動地轉換Integer為int然后加上10,接著將其轉換回Integer.。
類型安全的枚舉(Typesafeenums)
類型安全枚舉提供下列特性:
他們提供編譯時類型安全。
他們都是對象,因此你不需要將他們放入集合中。
他們作為一種類的實現,因此你可以添加一些方法。
他們為枚舉類型提供了合適的命名空間。
他們打印的值具有情報性(informative)― 如果你打印一個整數枚舉(intenum),你只是看見一個數字,它可能并不具有情報性。
例一:
enum Season { winter, spring, summer, fall }
例二:
public enum Coin {
penny(1), nickel(5), dime(10), quarter(25);
Coin(int value) { this.value = value; }
private final int value;
public int value() { return value; }
}
靜態導入(Static import)
靜態導入使代碼更易讀。通常,你要使用定義在另一個類中的常量(constants),像這樣:
importorg.yyy.pkg.Increment;
class Employee {
public Double calculateSalary(Double salary{
return salary + Increment.INCREMENT * salary;
}
}
當時使用靜態導入,我們無需為常量名前綴類名就能使用這些常量,像這樣:
import static org.yyy.pkg.Increment;
class Employee {
public Double calculateSalary(Double salary{
return salary + INCREMENT * salary;
}
}
注意,我們可以調用INCREMENT這一常量而不要使用類名Increment.。
元數據(Metadata)
元數據特征志于使開發者們借助廠商提供的工具可以進行更簡易的開發。看一看Listing E.中的代碼。
Listing E
importorg.yyy.hr;
public interface EmployeeI extends Java.rmi.Remote {
public String getName()
throwsJava.rmi.RemoteException;
public String getLocation ()
throwsJava.rmi.RemoteException;
}
public class EmployeeImpl implements EmployeeI {
public String getName(){
}
public String getLocation (){
}
}
通過元數據的支持,你可以改寫Listing E中的代碼為:
importorg.yyy.hr;
public class Employee {
@Remote public String getName() {
...
}
@Remote public public String getLocation() {
...
}
}
正像你所看到的,所有樣板化的代碼都不見了。
這些新特性和規格說明將在JDK1.5中實現。它將提供Java編程社區更多的選擇以編寫魯棒的、可擴展的代碼。認真的Java編程人員將感到著手去熟悉這一Java編程語言的新版本是很有益的。
本文來自:http://www.linuxpk.com/43851.html
Java2標準版(Java 2 Platform, Standard Edition, J2SE)1.5即將正式推出,這一次的版本更新不同于以往,它帶來了很多里程碑式的革新,SUN將其綽號取名為“虎”。這一次的變革將是Java誕生以 來從未有過的,它給我們帶來了耳目一新的感覺。下面我們就來欣賞一下其中的部分典型變化:
1.自動包裝和解包(Autoboxing and unboxing)
代碼示例
往一個ArrayList中加入一個整數,1.5版本以前的版本寫法是:
List list = new ArrayList();
list.add( new Integer( 10 ) );
而在1.5版本中可以寫為:
list.add( 10 );
因為,在1.5版本中,對一個整數進行包裝,使之成為一個Integer對象(即包裝,boxing),然后加入到一個ArrayList中的做法被認 為是沒有必要的,反之,解包(unboxing)的做法也是沒有必要的,這樣的代碼只是增加了程序的文本長度而已,所以1.5版本支持了自動包裝和解包操 作,對于bool/Boolean,byte/Byte,double/Double,short/Short,int/Integer, long/Long,float/Float的相應包裝/解包操作都進行了支持,從而使代碼變得簡單。
2.更優化的循環語句(The inhanced for loop)
代碼示例
一個典型的遍歷數組的循環語句,1.5版本以前的寫法是:
for ( Iterator iterator = list.iterator(); iterator.hasNext(); )
{
Integer n = (Integer)iterator.next();
...
}//for
而在1.5版本中可以寫為:
for ( Integer n : list )
{
...
}//for
顯然1.5版本的寫法比以前是大大簡化了,但是在需要修改集合,比如刪除其中元素時不能采用這種寫法。之所以Java1.5版本沒有象C#那樣干脆定義 一個foreach關鍵詞,主要是因為SUN認為增加一個專門的關鍵詞成本太高了(too costly)。但1.4版本中就曾經增加了assert關鍵詞,1.5版本中也新增加了enum關鍵詞,因此這一解釋恐怕并不那么令人信服。
3.參數可變的方法和printf
代碼示例
當不能確定一個方法的入口參數的個數時,以往版本的Java中,通常的做法是將多個參數放在一個數組或者對象集合中作為參數來傳遞,1.5版本以前的寫法是:
int sum(Integer[] numbers)
{
int nSum = 0;
for(int i: numbers)
nSum += i;
return nSum;
}
...
//在別處調用該方法
sum(new Integer[] {12,13,20});
而在1.5版本中可以寫為:
int sum(Integer... numbers)
{
int nSum = 0;
for(int i: numbers)
nSum += i;
return nSum;
}
...
//在別處調用該方法
sum(12,13,20);
顯然,1.5版本的寫法更為簡易,也更為直觀,尤其是方法的調用語句,不僅簡化很多,而且更符合通常的思維方式,更易于理解。
1.5版本自身就有一個應用該特征的典型例子,即C風格的格式化輸出方法――printf。
代碼示例
輸出一個加法算式,1.5版本以前的寫法是:
int x = 5;
int y = 7;
int nSum = x + y;
System.out.println(x + " + " + y + " = " + nSum);
而在1.5版本中可以寫為:
System.out.printf("%d + %d = %d"n", x, y, nSum);
以上兩種寫法的輸出結構是一樣的,即“5 + 7 = 12”。
這種改變不僅僅是形式上的,printf還可以提供更為靈活、強大的輸出功能,比如限定按照兩位整數的形式輸出,可以寫為 “System.out.printf("%02d + %02d = %02d"n", x, y, nSum);”,輸出結果將是“05 + 07 = 12”。
4.枚舉
代碼示例
構建一個表示色彩的枚舉,并賦值,在1.5版本中可以寫為:
public enum MyColor{ Red, Yellow, Blue }
MyColor color = MyColor.Red;
for ( MyColor mycolor : MyColor.values() )
System.out.println( mycolor );
以往的Java版本中沒有enum關鍵詞,1.5版本中終于加入了進來,這確實是一個令人高興的改進。此外,enum還提供了一個名為values() 的靜態方法,用以返回枚舉的所有值的集合。所以,以上程序的輸出結果是把“Red”、“Yellow”、“Blue”分行輸出。
而 enum提供的靜態方法valueOf()則將以字符串的形式返回某一個具體枚舉元素的值,比如“MyColor.valueOf(“Red”)”會返回 “Color.Red”。靜態方法name()則返回某一個具體枚舉元素的名字,比如“MyColor.Red.name()”會返回“Red”。類似的 方法還有不少。此外,enum自身還可以有構造方法。
5.靜態引用
代碼示例
當我們要獲取一個隨即數時,1.5版本以前的寫法是:
import java.lang.Math; //程序開頭處
...
double x = Math.random();
而在1.5版本中可以寫為:
import static java.lang.Math.random; //程序開頭處
…
double x = random();
靜態引用使我們可以象調用本地方法一樣調用一個引入的方法,當我們需要引入同一個類的多個方法時,只需寫為“import static java.lang.Math.*”即可。這樣的引用方式對于枚舉也同樣有效。
6.總結
以上對J2SE1.5的部分新特征做了一些簡單的介紹。總而言之,1.5版本的Java確實給我們帶來了很多令人激動的變革,如同以上介紹的那樣,很多功能以前的版本也能實現,但是不能實現得這樣簡單、漂亮。相信這次變革會給Java帶來更多的追隨者。
本文來自:http://www.linuxpk.com/43860.html
泛型(Generics)--為集合(collections)提供編譯時類型安全,無需每刻從Collections取得一個對象就進行強制轉換(cast)
增強的“for”循環(Enhanced For loop)--減少迭代器(iterator)的潛在錯誤(error-proneness)
自動置入/自動取出(Autoboxing/unboxing)--無需在基本類型(primitive types)(例如double)和包裝類型(wrapper types)(例如Double)之間人工地進行轉換。
類型安全的枚舉(Typesafeenums)--提供類型安全枚舉模式的各項好處。
靜態導入(Static import)--無需在使用其他類的靜態成員變量前綴其類名.這將使得代碼更為簡潔。
元數據(Metadata)--使編程人員避免編寫樣板化代碼(boiler plate code),并提供機會進行宣告式程式設計(declarative programming)。
讓我們詳細討論每個新特性,并看一些例子。
泛型(Generics)
泛型是JDK1.5中一個最“酷”的特征。通過引入泛型,我們將獲得編譯時類型的安全和運行時更小地拋出ClassCastExceptions的可 能。在JDK1.5中,你可以聲明一個集合將接收/返回的對象的類型。在JDK1.4中,創建雇員名字的清單(List)需要一個集合對象,像下面的語 句:
List listOfEmployeeName = new ArrayList();
在JDK1.5中,你將使用下面語句
List<String> listOfEmployeeName = new ArrayList<String>();
最“酷”的是,如果你試圖插入非string類型的值,你將在編譯時發現并且修正這類問題。沒有泛型,你會發現這樣一個bug,當你的客戶調用后會告訴你,你所編寫的程序拋出ClassCastException異常而崩潰。
另外,當你從集合中得到一個元素時你無需進行強制轉換。故原先為:
String employeeName = ((String) listOfEmployee.get(i));
而下面的語句將比上面的更加簡單:
String employeeName = listOfEmployee.get(i);
不清楚對象的類型而強制轉換對象是不合理的,并且更重要的是,它將在運行時失敗。假使用戶無意間傳入一個包含string buffers類型而非string類型的集合,那結果會怎樣呢。在Listing A中,客戶被要求傳入一個編譯器無法強制的strings類型集合。Listing B中顯示了同樣的方法使用泛型是如何實現的。
Listing A
staticbooleancheckName(Collection employeeNameList, String name) {
for (Iteratori = employeeNamList.iterator(); i.hasNext(); ) {
String s = (String) i.next();
if(s.equals(name)){
return true;
//print employee name here ......
}
}
return false;
}
Listing B
staticbooleancheckName(Collection<String> employeeNameList, String name) {
for (Iteratori = employeeNamList.iterator(); i.hasNext(); ) {
if(i.next().equals(name)){
return true;
//print employee name here ......
}
}
return false;
}
現在,通過方法簽名可以清楚知道輸入集合必須只能包含strings。如果客戶試圖傳入一個包含string buffers的集合,程序將不會編譯。同時注意,該方法不包含任何強制轉換。它只需要短短一行,一旦你習慣泛型后,它也更加清晰。
在JDK當前版本下的For循環語法如下:
void printAll(Collection c) {
for (Iteratori = c.iterator(); i.hasNext(); ) {
Employee emp = (Employee)i.next();
System.out.println(emp.getName());
}
}
現在,用增強的For語句實現相同方法:
voidprintAll(Collection c) {
for (Object o : c)
System.out.println((TimerTask)o).getName());
}
在這類For循環中,你應該將":"看成"in",所以,在該例中可以看成"for Object o in c"。你可以發現這種For循環更具可讀性。
自動置入/自動取出(Autoboxing/unboxing)
Java有基本數據類型,在這些基本數據類型周圍又有包裝類。通常,編程人員需要將一種類型轉換成另一種。看看Listing C.中的代碼片斷。
Listing C
public class Employee {
private static final Integer CHILD = new Integer(0);
public static void main(String args[]) {
//code for adding n to an Integer
int n=10;
Integer age= new Integer(30);
Integer ageAfterTenYear= new Integer(age.intValue +10);
}
}
請注意,用于計算ageAfterTenYear的內循環代碼看上去是多么雜亂。現在,在Listing D.中看看相同的程序使用autoboxing重寫后的樣子。
Listing D
public class Employee {
public static void main(String args[]) {
int n=10;
Integer age= new Integer(30);
Integer ageAfterTenYear= age +10;
}
}
有一件事值得注意的:在先前,如果你取出(unbox)Null值,它將變為0。在次代碼中,編譯器將自動地轉換Integer為int然后加上10,接著將其轉換回Integer.。
類型安全的枚舉(Typesafeenums)
類型安全枚舉提供下列特性:
他們提供編譯時類型安全。
他們都是對象,因此你不需要將他們放入集合中。
他們作為一種類的實現,因此你可以添加一些方法。
他們為枚舉類型提供了合適的命名空間。
他們打印的值具有情報性(informative)― 如果你打印一個整數枚舉(intenum),你只是看見一個數字,它可能并不具有情報性。
例一:
enum Season { winter, spring, summer, fall }
例二:
public enum Coin {
penny(1), nickel(5), dime(10), quarter(25);
Coin(int value) { this.value = value; }
private final int value;
public int value() { return value; }
}
靜態導入(Static import)
靜態導入使代碼更易讀。通常,你要使用定義在另一個類中的常量(constants),像這樣:
importorg.yyy.pkg.Increment;
class Employee {
public Double calculateSalary(Double salary{
return salary + Increment.INCREMENT * salary;
}
}
當時使用靜態導入,我們無需為常量名前綴類名就能使用這些常量,像這樣:
import static org.yyy.pkg.Increment;
class Employee {
public Double calculateSalary(Double salary{
return salary + INCREMENT * salary;
}
}
注意,我們可以調用INCREMENT這一常量而不要使用類名Increment.。
元數據(Metadata)
元數據特征志于使開發者們借助廠商提供的工具可以進行更簡易的開發。看一看Listing E.中的代碼。
Listing E
importorg.yyy.hr;
public interface EmployeeI extends Java.rmi.Remote {
public String getName()
throwsJava.rmi.RemoteException;
public String getLocation ()
throwsJava.rmi.RemoteException;
}
public class EmployeeImpl implements EmployeeI {
public String getName(){
}
public String getLocation (){
}
}
通過元數據的支持,你可以改寫Listing E中的代碼為:
importorg.yyy.hr;
public class Employee {
@Remote public String getName() {
...
}
@Remote public public String getLocation() {
...
}
}
正像你所看到的,所有樣板化的代碼都不見了。
這些新特性和規格說明將在JDK1.5中實現。它將提供Java編程社區更多的選擇以編寫魯棒的、可擴展的代碼。認真的Java編程人員將感到著手去熟悉這一Java編程語言的新版本是很有益的。
本文來自:http://www.linuxpk.com/43851.html
Java2標準版(Java 2 Platform, Standard Edition, J2SE)1.5即將正式推出,這一次的版本更新不同于以往,它帶來了很多里程碑式的革新,SUN將其綽號取名為“虎”。這一次的變革將是Java誕生以 來從未有過的,它給我們帶來了耳目一新的感覺。下面我們就來欣賞一下其中的部分典型變化:
1.自動包裝和解包(Autoboxing and unboxing)
代碼示例
往一個ArrayList中加入一個整數,1.5版本以前的版本寫法是:
List list = new ArrayList();
list.add( new Integer( 10 ) );
而在1.5版本中可以寫為:
list.add( 10 );
因為,在1.5版本中,對一個整數進行包裝,使之成為一個Integer對象(即包裝,boxing),然后加入到一個ArrayList中的做法被認 為是沒有必要的,反之,解包(unboxing)的做法也是沒有必要的,這樣的代碼只是增加了程序的文本長度而已,所以1.5版本支持了自動包裝和解包操 作,對于bool/Boolean,byte/Byte,double/Double,short/Short,int/Integer, long/Long,float/Float的相應包裝/解包操作都進行了支持,從而使代碼變得簡單。
2.更優化的循環語句(The inhanced for loop)
代碼示例
一個典型的遍歷數組的循環語句,1.5版本以前的寫法是:
for ( Iterator iterator = list.iterator(); iterator.hasNext(); )
{
Integer n = (Integer)iterator.next();
...
}//for
而在1.5版本中可以寫為:
for ( Integer n : list )
{
...
}//for
顯然1.5版本的寫法比以前是大大簡化了,但是在需要修改集合,比如刪除其中元素時不能采用這種寫法。之所以Java1.5版本沒有象C#那樣干脆定義 一個foreach關鍵詞,主要是因為SUN認為增加一個專門的關鍵詞成本太高了(too costly)。但1.4版本中就曾經增加了assert關鍵詞,1.5版本中也新增加了enum關鍵詞,因此這一解釋恐怕并不那么令人信服。
3.參數可變的方法和printf
代碼示例
當不能確定一個方法的入口參數的個數時,以往版本的Java中,通常的做法是將多個參數放在一個數組或者對象集合中作為參數來傳遞,1.5版本以前的寫法是:
int sum(Integer[] numbers)
{
int nSum = 0;
for(int i: numbers)
nSum += i;
return nSum;
}
...
//在別處調用該方法
sum(new Integer[] {12,13,20});
而在1.5版本中可以寫為:
int sum(Integer... numbers)
{
int nSum = 0;
for(int i: numbers)
nSum += i;
return nSum;
}
...
//在別處調用該方法
sum(12,13,20);
顯然,1.5版本的寫法更為簡易,也更為直觀,尤其是方法的調用語句,不僅簡化很多,而且更符合通常的思維方式,更易于理解。
1.5版本自身就有一個應用該特征的典型例子,即C風格的格式化輸出方法――printf。
代碼示例
輸出一個加法算式,1.5版本以前的寫法是:
int x = 5;
int y = 7;
int nSum = x + y;
System.out.println(x + " + " + y + " = " + nSum);
而在1.5版本中可以寫為:
System.out.printf("%d + %d = %d"n", x, y, nSum);
以上兩種寫法的輸出結構是一樣的,即“5 + 7 = 12”。
這種改變不僅僅是形式上的,printf還可以提供更為靈活、強大的輸出功能,比如限定按照兩位整數的形式輸出,可以寫為 “System.out.printf("%02d + %02d = %02d"n", x, y, nSum);”,輸出結果將是“05 + 07 = 12”。
4.枚舉
代碼示例
構建一個表示色彩的枚舉,并賦值,在1.5版本中可以寫為:
public enum MyColor{ Red, Yellow, Blue }
MyColor color = MyColor.Red;
for ( MyColor mycolor : MyColor.values() )
System.out.println( mycolor );
以往的Java版本中沒有enum關鍵詞,1.5版本中終于加入了進來,這確實是一個令人高興的改進。此外,enum還提供了一個名為values() 的靜態方法,用以返回枚舉的所有值的集合。所以,以上程序的輸出結果是把“Red”、“Yellow”、“Blue”分行輸出。
而 enum提供的靜態方法valueOf()則將以字符串的形式返回某一個具體枚舉元素的值,比如“MyColor.valueOf(“Red”)”會返回 “Color.Red”。靜態方法name()則返回某一個具體枚舉元素的名字,比如“MyColor.Red.name()”會返回“Red”。類似的 方法還有不少。此外,enum自身還可以有構造方法。
5.靜態引用
代碼示例
當我們要獲取一個隨即數時,1.5版本以前的寫法是:
import java.lang.Math; //程序開頭處
...
double x = Math.random();
而在1.5版本中可以寫為:
import static java.lang.Math.random; //程序開頭處
…
double x = random();
靜態引用使我們可以象調用本地方法一樣調用一個引入的方法,當我們需要引入同一個類的多個方法時,只需寫為“import static java.lang.Math.*”即可。這樣的引用方式對于枚舉也同樣有效。
6.總結
以上對J2SE1.5的部分新特征做了一些簡單的介紹。總而言之,1.5版本的Java確實給我們帶來了很多令人激動的變革,如同以上介紹的那樣,很多功能以前的版本也能實現,但是不能實現得這樣簡單、漂亮。相信這次變革會給Java帶來更多的追隨者。
本文來自:http://www.linuxpk.com/43860.html