loveispopular

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  9 随笔 :: 0 文章 :: 0 评论 :: 0 Trackbacks
java1.5新特性

语法改动比较大的是泛型编程。使用泛型编程需要在声明的时候提供附加的声明信息。比如:
List words = new ArrayList();
需要替换成:
List<String> words = new ArrayList<String>();
这样做的一个优点是,如果你插入数组的数据类型不是字符串的话,你就可以在编译的时候发现和解决这个bug。如果不使用上面的声明,这个bug不可能在编译的时候发现,程序运行后会出现ClassCastException 的错误。
另一个好处是:你不在需要担心集合中的元素超出了范围:
String title = ((String) words.get(i)).toUppercase();
使用:
String title = words.get(i).toUppercase();
你能简单的介绍一下这些J2SE 1.5中改变最大的六个方面吗?
好的,
• 泛型编程 – 提供集合对象的编译时安全类型检查。
• 增强 for 循环 - 编程更容易,去掉了修正了导致迭代出错的问题。
• 装箱/拆箱 - 原始类型(int)和封装类型(Integer)的转换更容易。
• 类型安全的枚举 – 提供了最常使用的类型安全的枚举模式。(Effective Java, Item 21)
• 静态导入Static import - Lets you avoid qualifying static members with class names, without the shortcomings of the Constant Interface antipattern (Effective Java, Item 17).
• Metadata – 避免编写描述信息的代码,实现“声明”编程的模式。程序员声明需要做什么,然后由相关的工具来完成具体的工作。

一、泛型编程: 比如,过滤一个集合中的元素,现在的做法和j2se1.5中的做法有什么不同呢?
现在的做法是:
/**
* 从一个指定的集合中去掉一个4个字符的元素。
*/
static void expurgate(Collection c) {
for (Iterator i = c.iterator(); i.hasNext(); ) {
String s = (String) i.next();
if(s.length() == 4)
i.remove();
}}
上面的代码,有些缺陷,在运行的过程中可能出错。比如:在集合中如果包含一个StringBuffer类型的数据。
以后可以这样做:
static void expurgate(Collection<String> c) {
for (Iterator<String> i = c.iterator(); i.hasNext(); )
if (i.next().length() == 4)
i.remove();
}
二、增强的for循环!
一个集合中元素的迭代,原来的做法繁琐。J2SE1.5中大多数情况下你不需要使用Iterate 来遍历一个集合。增强的for循环,让编译器来完成具体的迭代工作。比如:
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).close();
}
注意:上面的冒号,它表示:in。在C#中或者很自然的一个替代是:foreach 和in 。但是考虑到兼容性,我们没有那样做。
泛型编程和增强的for结合后会是什么结果呢?
上面的例子中的代码,可以用下面的代码表示:
void cancelAll(Collection<TimerTask> c) {
for (TimerTask task : c)
task.cancel();
}
三、什么是装箱?
大家知道,java语言中有两种数据类型:一些是基本数据类型,另一些是对象引用类型。基本的数据类型无法直接放入到集合中,除非做相应的类型转换。这种转换非常枯燥。
举例:map数据类型的key用来存储单词,value用来存储单词重复的次数。这是一个计算单词出现频率的小程序。
public class Freq {
private static final Integer ONE = new Integer(1);
public static void main(String args[]) {
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);
}
}
下面是采用装箱,泛型,和增强的for循环后的代码:
public class Freq {
public static void main(String args[]) {
Map<String, Integer> m = new TreeMap<String, Integer>();
for (String word : args)
m.put(word, m.get(word) 1);
System.out.println(m);
}
}
需要注意:上面的程序假定拆箱为null的时候,值为0。

J2SE1.5的新特点(下)
类型安全的枚举比以前的枚举有什么优点呢?
有如下特点:
• 提供编译时int枚举的安全检查,同时不再提供其他类型安全检查。
• 提供了枚举的命名空间
• 可以直接把它们放到集合中。
• 因为他们本质上是类,你可以向里面添加属性和方法。
上面的这些特点的确不错。能讲讲类型安全的枚举语言的特点和类型安全的枚举模式的关系吗?
一般来说:上面的那些特点简单的从语义上支持了模式。看下面的例子,和C/C++ 枚举的声明很相似:
enum Season { winter, spring, summer, fall }
声明虽然相似,但是确让编译器实现了上面提到的许多特性。你还可以把Season用到switch的判断语句中。
请举例说明“类型安全的枚举”的优点。
下面是一个表示美分枚举类型的例子。
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; }
}
这是个创举。我们定义了value来作为读取Coin的公共变量。在枚举的构造函数中可以在声明枚举实例的时候来初始化它。
让我们看看进一步使用这个枚举的例子。
我把不的呢。下面的程序打印一个表格和其中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 Coin.penny:   return CoinColor.copper;
case Coin.nickel: return CoinColor.nickel;
case Coin.dime:
case Coin.quarter: return CoinColor.silver;
default: throw new AssertionError("Unknown coin: " + c);
}
}
}
太棒了。那么静态引入static import 的功能对程序员有什么帮助呢?
首先他避免了程序员使用前缀的静态成员。以前常见的的一个替代的做法是:
// "Constant Interface" antipattern – 不推荐的做法
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;
...
}
}
上面的做法达到了效果,可是却违背了一些设计原则。接口是用来定义方法和类型的,不是提供常量声明的。而且只是由Guacamole使用的常量也暴露给了使用其的客户端。
静态引入功能提供了一个简单的实现。这个功能和包的import功能类似。
import static org.iso.Physics.*;

class Guacamole {
public static void main(String[] args) {
double molecules = AVOGADROS_NUMBER * moles;
...
}
}
明白,那么什么是元数据类型metadata的功能呢?
使用metadata和第三方工具提供商可以让程序员自己的日子好过点。
以前许多发布API需要大量的描述信息。比如:定义一个JAX-RPC 网络服务API你需要提供其接口和实现类。如下:
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) {
...
}
}
使用元数据功能,你可以节省大量的工作。你所需要做的是在代码上加上特殊的注释。你所使用的开发工具可是使用这些注释自动生成相关的代吗。如下所示:
import javax.xml.rpc.*;

public class CoffeeOrder {
@Remote public Coffee [] getPriceList() {
...
}
@Remote public String orderCoffee(String name, int quantity) {
...
}
}

posted on 2009-05-24 15:41 george_chen 阅读(151) 评论(0)  编辑  收藏

只有注册用户登录后才能发表评论。


网站导航: