Java5更新原有代码

来源:互联网 发布:淘宝靠谱的iphone店铺 编辑:程序博客网 时间:2024/05/01 13:09

        在学习编程的过程中,我觉得不止要获得课本的知识,更多的是学习面对问题,如何解决,这样我们才能走在最前方,更多Java学习,请搜索疯狂Java;

  你不必重新改写应用程序也能利用Java 5的新功能。我们为你介绍不必改写大量代码就能实现更新的方法。

  你曾经得到一段以Java 1.4或更早版本编写的代码,并希望改写它以进行开发吗?这段代码当然能够在Java SE 5上正常运行,但详细了解JavaSE 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 unsafeoperations.

  Note: Recompile with -Xlint:unchecked fordetails.

  在编译器标记中增加-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了解一些有用的知识,而不必钻研那一领域。

  疯狂Java培训采用针对性培养,全面提升学员就业能力,重点加强训练职业素质。

 

原创粉丝点击