1、重要的语言变化 
l         泛型(Generics) 
l         增强型循环(foreach) 
l         自动封箱(Autoboxing)和解箱(Unboxing) 
l         安全类型的Enums 
l         Varargs 
l         静态import 
l         Annotations 
  
2、泛型(Generics) 
(1)问题 
l         从集合中获得元素时,必须进行类型转换: 
Ø         类型转换是麻烦的 
Ø         类型转换是不安全的,可能在运行时发生类型转换失败 
l         为什么不能做的更好:告诉编译器集合中元素的类型? 
Ø         让编译器加入类型转换功能 
Ø         编译器会保证类型转换的成功 
(2)过滤集合的例子 
// Removes 4-letter words from c; elements must be strings static void expurgate(Collection c) {       for (Iterator i = c.iterator(); i.hasNext();) {              String s = (String) i.next();               if (s.length() == 4) {                i.remove();               }        } }  
(3)使用泛型 
// Removes 4-letter words from c static void expurgate(Collection<String> c) {       for (Iterator<String> i = c.iterator(); i.hasNext();) {              if (i.next().length() == 4) {                i.remove();               }        } }  
l         更加清晰和安全 
l         没有类型转换、额外的括号和临时变量 
l         提供编译时的类型检查 
(4)泛型不是模板 
l         没有膨胀的代码 
l         没有可怕的复杂性 
l         没有模板元程序 
l         简单的提供编译时类型安全性和消除类型转换 
  
3、增强型循环(foreach) 
(1)问题 
l         遍历集合是麻烦的事 
l         Iterator通常只有在获取元素时才会用到 
l         使用Iterator倾向于错误: 
Ø         Iterator变量在循环中出现3次 
Ø         使你有两次出错的机会 
Ø         通常的拷贝粘贴错误 
l         为什么不做的更好,如果能让编译器来为你处理Iterator? 
(2)通常访问集合元素的例子 
void cancelAll(Collection c) {       for (Iterator i = c.iterator(); i.hasNext();) {              TimerTask tt = (TimerTask) i.next();               tt.cancel();        } }  
(3)使用增强循环的例子 
void cancelAll(Collection c) {       for (Object o : c) {              ((TimerTask) o).cancel();        } }  
l         更加清晰和安全 
l         和Iterator无关 
l         不可能使用错误的Iterator 
(4)结合泛型的例子 
void cancelAll(Collection<TimerTask> c) {       for (TimerTask task : c) {              task.cancel();        } }  
l         更加简洁、清晰和安全 
l         代码准确表达它所要做的 
(5)对数组同样适合 
//Returns the sum of the elements of a int sum(int[] a) {       int result = 0;        for (int i : a) {              result += i;        }        return result; }  
l         消除使用数组索引的错误 
l         具有前面所述的优点 
(6)灵活的嵌套Iterator 
l         通常的例子 
List suits = ...; List ranks = ...; List sortedDeck = new ArrayList(); // Broken - throws NoSuchElementException! for (Iterator i = suits.iterator(); i.hasNext();) {       for (Iterator j = ranks.iterator(); j.hasNext();) {              sortedDeck.add(new Card(i.next(), j.next()));        } } // Fixed - a bit ugly for (Iterator i = suits.iterator(); i.hasNext();) {       Suit suit = (Suit) i.next();        for (Iterator j = ranks.iterator(); j.hasNext();) {              sortedDeck.add(new Card(suit, j.next()));        } }  
l         使用增强循环简单而灵活 
for (Suit suit : suits) {       for (Rank rank : ranks) {              sortedDeck.add(new Card(suit, rank));        } }  
  
4、自动封箱(Autoboxing)和解箱(Unboxing) 
(1)问题 
l         不能将int放入集合,必须使用Integer 
l         在获取时转换回来又是麻烦的事 
l         由编译器来做这些事不是更好吗? 
(2)使用通常方法创建一个频率表的例子 
public class Freq {       private static final Integer ONE = new Integer(1);          public static void main(String[] args) {              // Maps word (String) to frequency (Integer)               Map m = new TreeMap();               for (int i = 0; i < args.length; i++) {                Integer freq = (Integer) m.get(args[i]);                 m.put(args[i], (freq == null ? ONE : new Integer(                          freq.intValue() + 1)));               }               System.out.println(m);        } }  
(2)结合自动封箱、泛型和增强循环的例子 
public class Freq {       public static void main(String[] args) {              Map<String, Integer> m = new TreeMap<String, Integer>();               for (String word : args) {                Integer freq = m.get(word);                 m.put(word, (freq == null ? 1 : freq + 1));               }               System.out.println(m);        } }  
  
5、安全类型的Enums 
(1)标准的int Enum模式 
public class Almanac {       public static final int SEASON_WINTER = 0;        public static final int SEASON_SPRING = 1;        public static final int SEASON_SUMMER = 2;        public static final int SEASON_FALL = 3;         ... // Remainder omitted }  
l         缺点: 
Ø         不是安全类型 
Ø         没有名字空间:必须要有常量前缀 
Ø         脆弱性:常量被编译到客户程序中 
Ø         打印出的值不提供信息 
(2)安全类型的Enum模式的例子 
import java.io.Serializable; import java.util.Arrays; import java.util.Collections; import java.util.List;   public final class Season implements Comparable, Serializable {         private final String name;          public String toString() {              return name;        }          private Season(String name) {              this.name = name;        }          public static final Season WINTER = new Season("winter");       public static final Season SPRING = new Season("spring");       public static final Season SUMMER = new Season("summer");       public static final Season FALL = new Season("fall");         private static int nextOrdinal = 0;        private final int ordinal = nextOrdinal++;          public int compareTo(Object o) {              return ordinal - ((Season) o).ordinal;        }          private static final Season[] PRIVATE_VALUES = { WINTER, SPRING, SUMMER,                FALL };          public static final List VALUES = Collections.unmodifiableList(Arrays                 .asList(PRIVATE_VALUES));          private Object readResolve() {              // Canonicalize               return PRIVATE_VALUES[ordinal];        } }  
l         基本想法:使用导出自定义类型的常量,不提供public构造方法 
l         修正上面所有的缺点 
l         其它优点: 
Ø         能够添加任意的方法、域变量 
Ø         能够实现接口 
l         缺点: 
Ø         代码冗长 
Ø         容易出错:每个常量出现3次 
Ø         不能在switch语句中使用 
l         为什么不能做的更好,由编译器来处理? 
(3)安全类型的Enum结构 
l         编译器支持安全类型的Enum模式 
l         类似典型的Enum(就象C、C++) 
Ø         enum Season { WINTER, SPRING, SUMMER, FALL } 
l         更大强大: 
Ø         安全类型的Enum模式的所有优点 
Ø         能够在switch语句中使用 
(4)结合泛型和增强循环的Enum例子 
enum Suit { CLUBS, DIAMONDS, HEARTS, SPADES }enum Rank { DEUCE, THREE, FOUR, FIVE, SIX, SEVEN,        EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE } List<Card> deck = new ArrayList<Card>(); for (Suit suit : Suit.values()) {       for (Rank rank : Rank.values()) {              deck.add(new Card(suit, rank));        } } Collections.shuffle(deck);  
(5)有域变量、方法和构造方法的Enum例子 
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;        } }  
l         使用Coin的例子: 
public class CoinTest {       public static void main(String[] args) {              for (Coin c : Coin.values()) {                System.out.println(c + ": \t" + c.value() + "¢ \t" + color(c));               }        }          private enum CoinColor {              COPPER, NICKEL, SILVER        }          private static CoinColor color(Coin c) {              switch (c) {              case PENNY:                 return CoinColor.COPPER;               case NICKEL:                 return CoinColor.NICKEL;               case DIME:               case QUARTER:                 return CoinColor.SILVER;               default:                 throw new AssertionError("Unknown coin: " + c);              }        } }  
  
6、Varargs 
(1)问题 
l         编写具有任意数量参数的方法,必须使用数组 
l         创建和初始化数组是麻烦的事 
l         如果由编译器来实现不是更好? 
l         就象printf的基本用法一样 
(2)使用java.text.MessageFormat的例子 
Object[] arguments = {       new Integer(7),        new Date(),        "a disturbance in the Force" }; String result = MessageFormat.format(        "At {1,time} on {1,date}, there was {2} on planet "       + "{0,number,integer}.", arguments); 
(3)使用Varargs的例子 
String result = MessageFormat.format(        At {1,time} on {1,date}, there was {2} on planet "       + "{0,number,integer}.",       7, new Date(), "a disturbance in the Force");  
l         format方法的Varargs声明如下: 
public static String format(String pattern,                        Object... arguments)  
l         参数类型是Object[] 
l         调用者不需要使用Varargs语法 
  
7、静态import 
(1)使用类导出常量的例子 
public class Physics {       public static final double AVOGADROS_NUMBER = 6.02214199e23;        public static final double BOLTZMANN_CONSTANT = 1.3806503e-23;        public static final double ELECTRON_MASS = 9.10938188e-31; }  
l         客户程序需要使用限定来访问常量: 
double molecules = Physics.AVOGADROS_NUMBER * moles;  
(2)避免限定的错误方法 
// "Constant Interface" antipattern - do not use! public interface Physics {       public static final double AVOGADROS_NUMBER = 6.02214199e23;        public static final double BOLTZMANN_CONSTANT = 1.3806503e-23;        public static final double ELECTRON_MASS = 9.10938188e-31; }   public class Guacamole implements Physics {       public static void main(String[] args) {       double moles = ...;        double molecules = AVOGADROS_NUMBER * moles;         ... }  
l         存在的问题: 
Ø         滥用接口:不是用来定义类型的 
Ø         实现细节污染导出API 
Ø         使客户程序混乱 
Ø         创建长期的承诺 
Ø         如果编译器让我们避免限定名字不是更好吗? 
(3)解决:静态import 
l         类似包的导入 
l         导入类的静态成员 
l         可以单个也可以全部导入 
l         使用静态import的例子: 
import static org.iso.Physics.*; public class Guacamole {       public static void main(String[] args) {              double molecules = AVOGADROS_NUMBER * moles;               ...        } }  
(4)导入方法的例子(Math类) 
l         替代 
x = Math.cos(Math.PI * theta);  
成: 
x = cos(Math.PI * theta);  
(5)和Enum一起工作 
import static gov.treas.Coin.*; class MyClass {       public static void main(String[] args) {              int twoBits = 2 * QUARTER.value();               ...        } }  
  
8、元数据(Annotations) 
(1)问题 
l         许多API需要相当数量的样板文件,如JAX-RPC Web服务需要成对的接口和实现 
l         如果能够注视代码,使得工具能够生成样板文件不是更好? 
l         许多API需要附加的文件来进行维护,如Bean需要BeanInfo类文件 
l         如果能够注视代码,使得工具能够生成这些附加文件不是更好? 
(2)JAX-RPC Web服务的例子 
public interface CoffeeOrderIF extends java.rmi.Remote {       public Coffee [] getPriceList()               throws java.rmi.RemoteException;        public String orderCoffee(String name, int quantity)               throws java.rmi.RemoteException; } public class CoffeeOrderImpl implements CoffeeOrderIF {       public Coffee [] getPriceList() {              ...        }        public String orderCoffee(String name, int quantity) {              ...        } }  
(3)使用Annotations的例子 
import javax.xml.rpc.*; public class CoffeeOrder {       @Remote public Coffee [] getPriceList() {              ...        }        @Remote public String orderCoffee(String name, int quantity) {              ...        } }  
   
 
  |