Java1.5 規范并沒有很好得在新功能特性與程序可讀性之間提供一個很好得平衡,事實上,所有得新功能都可以用一種清楚,明確,可讀性良好并且與1.5之前的語法兼容的語法結構來表達.在這篇文章里,我會通過我所提議的三種語法來闡述這個觀點(翻譯到這里,
will不禁對本文作者肅然起敬,也預見到了本文的翻譯難度不小…-_-bb..)
New for Loop
由于許多開發者都希望對于collections和arrays的循環操作能有更緊湊的形式,所以Sun提出了一個新的for語句,包含了foreach的語法含義.
舊語法:void cancelAll(Collection c) { for (Iterator i = c.iterator(); i.hasNext(); ) { TimerTask tt = (TimerTask) i.next(); tt.cancel(); }}
新語法:void cancelAll(Collection c) { for (Object o : c) ((TimerTask)o).cancel();}
在新語法中,對集合對象的迭代操作更加緊湊了,但是用冒號來表示foreach顯得十分含糊.根據Sun的解釋是foreach使用的太過普遍(它是Perl,VBScript,Ruby,PHP和Tcl等語言中的關鍵字), 因此如果將它歸為關鍵字會給很多已完成的程序帶來問題,因為這些程序有可能使用foreach作為變量名或是方法名. 這個理由是合理的,但這并不意味著沒有其他比使用冒號更好的方法.
例如,為什么不添加一個eachof關鍵字,使得標準的for循環變為foreach循環,如下代碼所示:
void cancelAll(Collection c) { for (Object o = eachof c) ((TimerTask)o).cancel();}
不像foreach, eachof在各種主要的腳本語言中作為關鍵字使用的并不多,而且對于少數不幸使用了eachof作為方法/變量名的,也有javac ?Csource幫忙.
除了能更好的向后兼容關鍵字,這個方法還有以下幾個好處:
? Eachof也適用于其他的循環結構,尤其是對多個集合對象同時進行查詢.例如:
void cancelAll(Collection c, d, e) {
assert c.size() == d.size() == e.size();
while ((Object o = eachof c) != null)
{
((TimerTask)o).cancel();
((TimerTask) eachof d).cancel();
((TimerTask) eachof e).cancel();
}
}
? eachof的可讀性好,容易理解,與break和continue關鍵字一樣,它作用于最近的循環體.
以上是我的提議,其他朋友也可以使用另外的方法,關鍵是只要多花點時間,就可以發現更好的方法,僅僅是為了向后兼容而使用冒號來實現foreach循環,并不是個好方法.
Generics
Java1.5中最主要的特性就是泛函.通過它可以極大的增強靜態類型檢查功能,而且簡化了許多對于collection對象的繁瑣操作.有人認為Java應該遵循C++和STL中所使用的泛函語法,如下所示:
1.5之前的實現static void expurgate(Collection c) { for (Iterator i = c.iterator(); i.hasNext(); ) { String s = (String) i.next(); if(s.length() == 4) i.remove(); }}
1.5+的實現static void expurgate(Collection c) { for (Iterator i = c.iterator(); i.hasNext(); ) if (i.next().length() == 4) i.remove();}
然而java之所以成功,其中的一個原因就是James Gosling吸取了C++中的教訓,例如取消了類實現的多繼承.在實現泛函上,java應該繼續采用這個方法,用簡單清晰的語法和語義來實現Generic.
例如,許多程序員喜歡用花括號來表示泛函語法.Sun的提議認為這樣會混淆類型參數與數值參數,再多想一點,我們可以發現另外一個方法:將類型參數用一對括號包住,然后放在被類型參數所作用的元素前,如下代碼所示:
static void expurgate((String) Collection c) {
for ((String) Iterator i = c.iterator(); i.hasNext(); )
if (i.next().length() == 4)
i.remove();
}
這樣似乎與類型轉換又混在一起了,但是他們是出現在不同的上下文中的.而且,假如Java Generic真的如此實現的,也不會導致將此結構誤認為類型轉換.
可以將它理解為“Declaration Cast”,即在某處做一類型聲明來告訴編譯器,當從集合中取出某一元素時,自動(悄悄的..J)進行什么樣的類型轉換(這段翻譯的will好別扭,不過總算說通順了…)
根據這種提議,類型轉換操作符將一般化為類型表達式. 在賦值操作的上下文里,它表達類型轉換,而在類型聲明的上下文里,它描述的是泛函類型參數.兩種用法并不沖突.
有趣的是,這種方法類似與數組的聲明.例如:
String [] strings1 = new String [10];
(String) List strings2 = new (String) List;
List與數組變量的聲明語法上非常類似,除了數組聲明中缺少了一對括號.假如Java1.5中添加了靜態類型安全數組(誰能告訴will這是什么??),那么只要通過添加一對括號,就可以將它和標準數組區別開,從而統一了數組聲明與集合聲明的語法.
總的來說,上面的這種語法有如下幾點好處(inverted generics syntax該怎么翻譯?)
? 它盡量使用了已有的語法結構,程序員原有的對類型轉換的認識有助于認識新的語法
? 對比尖括號有更好的可讀性.當然,這只是個人的喜好.
? 不會帶來類型參數和參數變量重疊書寫.
? 它反映了在泛型系統中實際的發生的故事
? 它統一了泛型集合和數組的聲明語法
下面的例子集合了上面我所提議的兩種語法實現
Sun的實現方法void cancelAll(Collection c) { for (TimerTask task : c) task.cancel();}
我提議的方法:void cancelAll((Timertask) Collection c) { for (TimerTask task = eachof c) task.cancel();}
Variance
Java1.5最新提出的特點是Variance(如何翻譯?),它修正了java的類型系統中的一些缺陷,并且增加了靜態類型檢查的力度.關于Variance的具體介紹,大家可以參考Sun的官方文檔,我這里只是關注它的語法.
Variance的語法如下:
A covariant, or read-only list of Numbers as List<+Number>.
A contravariant, or write-only list of Numbers as List<-Number>.
A bivariant, read-write list of Numbers as List<*>.
An invariant list of Numbers as List<=Number>.
靜態安全數組的語法類似.
我認為這種語法是會令程序員感到困惑的,特別是那些對于variance的概念仍然不清楚的程序員(包括了正在翻譯的will)
我們知道,類的層次關系的表示是與習慣的閱讀順序一致的.例如,..Number表示從Number的所有超類到Number類,Number..代表從Number類到它的所有子類,Number相對兩點省略號的位置可以表明描述該類層次結構的方向.
在java或其他類C語言里,也是使用相類似的機制來描述先加后操作(++i)與先操作后加(i++)
下面的例子來自variance tutorial,用我所提議的語法結構重寫了一次
public abstract class Shape {
public abstract void drawOn (Canvas c)
}
public class Line extends Shape {
public int x, y, x2, y2
public void drawOn (Canvas c) { ... }
}
public class Polygon extends Shape {
private (Line) List lines;
public void drawOn (Canvas c) { ... }
}
public class Canvas {
public void draw (Shape s) {
s.drawOn (this)
}
// Covariant (read-only) list of shapes
public void drawAll ((Shape..) List shapes) {
for (Shape s = eachof shapes)
s.drawOn (this)
}
}
...
// copy from covariant list (read-only) to contravariant list (write-only)
public void copy ((Shape..) List from, (..Shape) List to) {
for (Shape s = eachof from)
to.add (s);
}
// copy from covariant array (read-only) to contravariant array (write-only)
public void copy ((Shape..)[] from, (..Shape)[] to) {
int i = 0;
for (Shape s = eachof from)
to[i++] = s;
}
這種寫法有以下好處:
? 形式緊湊,特別是有利于復雜的類型表達式.Shap..表示covariance,..Shape表示contravariance.
? 對于初學者,可以使用更清楚的語法:Shape..final,Object..Shape.而不需要去了解底層的類型理論.
? Javadoc可以給位置的表示方法提供更好的支持,從左到右的顯示類層次中,從子類到父類的關系.
原文:http://www.onjava.com/pub/a/onjava/2003/09/24/readable_java.html