如何用Java5更新原有代码
你不必重新改写应用程序也能利用Java 5的新功能。我们为你介绍不必改写大量代码就能实现更新的方法。
你曾经得到一段以Java 1.4或更早版本编写的代码,并希望改写它以进行开发吗?这段代码当然能够在Java SE 5上正常运行,但详细了解Java SE 5的新功能会使接下来的开发过程更加顺利。下面我们来了解一些应用那些功能的简单实例,以及如何以最小的争论来介绍它们。
我们首先从StringBuffer类开始,你可以在任何代码中找到这个连接字符串的类。下面是它的一个典型应用
StringBuffer sb=new StringBuffer();
sb.append("Some strings")
…
sb.append(someMethod());
String result=sb.toString();
StringBuffer看起来没什么特别,但它有一个难解的语义;它是线程安全的,所以你每次调用它的一个方法,都必须为它本身获得一个同步锁。现在,在大多数类型代码中,可能你不会有两个应用同样StringBuffer的线程,但StringBuffer仍然需要同步锁,这需要一小段时间。输入JavaSE 5的StringBuilder,它与StringBuffer相同,只有一点不同:它不是线程安全类,因此不需要获得同步锁。这是一个细微的性能改进,但执行起来很简单。
StringBuilder sb=new StringBuilder();
所有的其它方法与StringBuffer一样。按惯例,对于新代码,你应该使用StringBuilder,除非字符串确实由多线程组成。
如果你的代码由一系列'myString=myString+appendString;'类型的操作构成,那么你的确需要改变它。在Java中,'+'运算符将字符串串联起来,因为Java字符串不可改变,Java编译器在后台重写它,建立一个StringBuffer,在缓冲器中进行串联并返回结果字符串。如果你在进行实际的字符串处理,你就希望用StringBuilder来代替它,使其更加简洁。只有一种情况你不希望那样做:调试或日志代码
System.out.println("Got "+someInteger+" and "+someString+" on "+someDate
你不必优化它,但是Java SE 5推出了一个你可能希望使用的方法printf,使打印与格式化输出更加方便。下面的代码与printf等价
System.out.printf("Get %d and %s on %tc%n",someInteger,someString,someDate
如果你熟悉C语言的printf,对上面的代码就不会陌生。第一个自变量是一个格式化字符串,它使用%表示如何对下面的一个自变量进行格式化;因此%d意思是把第一个自变量打印为数字;%s指把第二个自变量打印为字符串,%c指把第三个自变量打印成格式化的日期。由于Java SE 5支持可变自变量,所以你可以向printf提交任何数量的自变量;而且它的格式化字符串指示也比C语言灵活。例如,你可以通过引用自变量的目录来多次引用一个自变量
System.out.printf("Get %d and %s on %tc, that's %1$d%n",someInteger
%1$d部分很重要。如果%后面是自变量的数字目录,以$结尾,接着是格式化指示,它就从那个特殊的自变量取值。结尾处的%n生成一个换行符;如果你熟悉C语言,就知道用可插入一个新行,因为%n生成一个独立于平台的换行符,而不是。查看Sun的Java文件了解格式化指示的全部内容。它是在printf中唯一被调用的Formatter类,你也可以在自己的代码中使用。
可变自变量是Java 5的新功能,如果你发现代码中全是为提交自变量而建立的数组,就可以使用它。如
process("print",new String);
这里的过程方法(process method)应该为
private void process(String cmd,String args) {
if(cmd.equals("print")) {
for(int i=0;I|||
它使用一个String数组提交数量可变的自变量给过程调用,但又希望调用方已建立了那个数组。Vararg支持让我们指定一个在自变量表中从未出现或出现多次的参数,并将它们变成一个数组,从而避免了这一需要。我们只需去掉过程声明中的""符号,并用"…"代替它即可。
private void process(String cmd,String... args) {
方法的其它部分不变。然后,调用过程会变得简单得多。
process("print","These","are","arguments");
它的巧妙之处在于,当你需要用Java 5自动管理它时,你仍然可以使用基于数组的调用类型;于是你可以更新方法声明,而不必修改调用代码。
在对一段代码进行重新开发时,我喜欢确信我没有对代码当前的运行方式做出假设。Java的静态类型非常适于这一点;但是如果我们处理集合,上述优点却不复存在。以下面这段代码为例
ArrayList list=new ArrayList();
list.add(new Integer(1000));
list.add(new Integer(200));
Iterator i=list.iterator();
while(i.hasNext()) {
Integer ni=(Integer)i.next();
System.out.println(ni);
}
这些都是合法的Java代码,在运行时间也能正常执行,只是在列表中增加了Integer(整数)实例。如果建立和处理操作依次发生,就可以容易的发现问题,但还是没有静态编译时间检查。JavaSE 5在Java语言中增加了"Generics"特性来解决这个问题。
如果你编译这段代码,首先你会看到一个警告
Note: Example.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
在编译器标记中增加-Xlint:unchecked,你会发现它在列表中增加了一个Integer类。
Example.java:41: warning: [unchecked] unchecked call to add(E) as a member of the raw type java.util.ArrayList
list.add(new Integer(1000));
Example.java:42: warning: [unchecked] unchecked call to add(E) as a member of the raw type java.util.ArrayList
list.add(new Integer(200));
这是因为ArrayList不知道自己会包含哪种类型的类,所以标记称之为"未经检查"(unchecked)。要解决这个问题,我们需要进入 ArrayList声明,清楚说明ArrayList包含什么类
ArrayList list=new ArrayList();|||
包含的类型在之间,在此例中为Integer类。现在这是一个清楚知道它包含Integer类的ArrayList,并会按此执行。因此如果你尝试执 行list.add(new Boolean(true))时,将会发生一个编译时间错误
Example.java:43: cannot find symbol
symbol: method add(java.lang.Boolean)
location: class java.util.ArrayList
list.add(new Boolean(true));
不过还是要注意,错误说明的是"没有这种增加布尔值的add方法",而不是"你在给一个只接受Integer类的ArrayList增加一个它不支持 的类。"
现在其它代码将按这一变化执行。但我们可以进一步改进它。注意,我们用到Iterator的next方法,它返回一个我们给我们所认为的类转型的 Object。理想情况下,我们希望转型尽可能的少。你们要让它明白它是一个循环Integer的Iterator。列表确实返回一个Iterator而非单独的Iterator,但这可能是向上转型到Iterator,且没有需要我们返回结果的特殊类型。解决办法就是终止向上转型
Iterator i=list.iterator();
现在我们可以删除循环中的转型操作。于是Iterator为next()方法返回一个Integer,所以转型更少
while(i.hasNext()) {
Integer ni=i.next();
System.out.println(ni);
}
为使代码更加简洁,值得指出的是,Java 5对循环进行了改进,使循环时的重复更加简化
for(Integer ni:list) {
System.out.println(ni);
}
应用这个语法,就不用担心Iterator过于松散了,它也照顾到编译器。在for()里面的冒号右边是可以不断重复的内容,如一列或一组集合或一个数组。在冒号左边是一个保存每次循环结果的声明。新的for语法使代码更易阅读。
说到Map集合,它有一个键和一个值,你可以指定二者的类型。假如我们希望HashMap以Integer为键,以String为值,可以这样指定
Map map=new HashMap();
利用这些generics知识,你可以强化你的Collections,并保证它们内容的类型安全。当然还有另一部分的generics知识,即建立你自己的generics类。但因为Collection类已经被一般化,你可以通过generics了解一些有用的知识,而不必钻研那一领域。
最后来了解一下静态输入。你可能遇到过这样的代码
import java.lang.Math;
…
result=Math.cos(Math.max(a,b)*Math.random()*Math.PI);
使用Math静态方法相当繁琐,每次你都必须指定Math类。静态输入允许你将一个类的所有静态声明输入到你的类的命名空间中,就像这样
import java.lang.Math.*;
…
result=cos(max(a,b)*random()*PI);
现在,可以应用这个功能来输入常量文件(如PI),但也不能静态输入所有的类,因为它会与你的方法名发生冲突;如果使用过多,还会使代 码难以理解。最好是少用静态输入,并在特别情况下使用它。例如,如果你想静态输入Math.PI,可以这样
import java.lang.Math.PI;
并在代码中把它作为PI引用。避免经常进行静态输入,即使这样做会生成更易于理解的代码。
如果你将这些Java 5语言元素应用到代码中,你的代码会变得更加严密,也更易于理解;同时易于理解的代码也更可能成为可重复利用的代码。
编辑推荐:
温馨提示:因考试政策、内容不断变化与调整,长理培训网站提供的以上信息仅供参考,如有异议,请考生以权威部门公布的内容为准! (责任编辑:长理培训)
点击加载更多评论>>