posts - 75,comments - 83,trackbacks - 0

 

增强的for循环

  为了迭代集合和数组,增强的for循环提供了一个简单、兼容的语法。有两点值得一提:   Init表达式

  在循环中,初始化表达式只计算一次。这意味着您通常可以移除一个变量声明。在这个例子中,我们必须创建一个整型数组来保存computeNumbers()的结果,以防止每一次循环都重新计算该方法。您可以看到,下面的代码要比上面的代码整洁一些,并且没有泄露变量numbers:
  未增强的For:  int sum = 0;  Integer[] numbers = computeNumbers();  for (int i=0; i < numbers.length ; i++)    sum += numbers[i];
 
  增强后的For:    int sum = 0;  for ( int number: computeNumbers() ) sum += number;
  局限性

  有时需要在迭代期间访问迭代器或下标,看起来增强的for循环应该允许该操作,但事实上不是这样,请看下面的例子:
for (int i=0; i < numbers.length ; i++) {    if (i != 0) System.out.print(",");    System.out.print(numbers[i]);}

  我们希望将数组中的值打印为一个用逗号分隔的清单。我们需要知道目前是否是第一项,以便确定是否应该打印逗号。使用增强的for循环是无法获知这种信息的。我们需要自己保留一个下标或一个布尔值来指示是否经过了第一项。   这是另一个例子:

for (Iterator<integer> it = n.iterator() ; it.hasNext() ; )    if (it.next() < 0)        it.remove();

  在此例中,我们想从整数集合中删除负数项。为此,需要对迭代器调用一个方法,但是当使用增强的for 循环时,迭代器对我们来说是看不到的。因此,我们只能使用java 5之前版本的迭代方法。   顺便说一下,这里需要注意的是,由于Iterator是泛型,所以其声明是Iterator<Integer>。许多人都忘记了这一点而使用了Iterator的原始格式。

  注释

  见http://www.blogjava.net/tangzurui/archive/2008/07/22/216555.html

        枚举


  enum非常像public static final int声明,后者作为枚举值已经使用了很多年。对int所做的最大也是最明显的改进是类型安全——您不能错误地用枚举的一种类型代替另一种类型,这一点和int不同,所有的int对编译器来说都是一样的。除去极少数例外的情况,通常都应该用enum实例替换全部的枚举风格的int结构。

  枚举提供了一些附加的特性。EnumMap和EnumSet这两个实用类是专门为枚举优化的标准集合实现。如果知道集合只包含枚举类型,那么应该使用这些专门的集合来代替Has                                   hMap或HashSet。

  大部分情况下,可以使用enum对代码中的所有public static final int做插入替换。它们是可比的,并且可以静态导入,所以对它们的引用看起来是等同的,即使是对于内部类(或内部枚举类型)。注意,比较枚举类型的时候,声明它们的指令表明了它们的顺序值。

  “隐藏的”静态方法

  两个静态方法出现在所有枚举类型声明中。因为它们是枚举子类上的静态方法,而不是Enum本身的方法,所以它们在java.lang.Enum的javadoc中没有出现。

  第一个是values(),返回一个枚举类型所有可能值的数组。

  第二个是valueOf(),为提供的字符串返回一个枚举类型,该枚举类型必须精确地匹配源代码声明。

  方法

  关于枚举类型,我们最喜欢的一个方面是它可以有方法。过去您可能需要编写一些代码,对public static final int进行转换,把它从数据库类型转换为JDBC URL。而现在则可以让枚举类型本身带一个整理代码的方法。下面就是一个例子,包括DatabaseType枚举类型的抽象方法以及每个枚举实例中提供的实现:
  public enum  DatabaseType {  Oracle {  public String getJdbcUrl() {...}  },  MySQL {  public String getJdbcUrl() {...}  };  public abstract String getJdbcUrl();  }
  现在枚举类型可以直接提供它的实用方法。例如:

DatabaseType dbType = ...;
String jdbcURL = dbType.getJdbcUrl();

  要获取URL,必须预先知道该实用方法在哪里。

  可变参数(Vararg)

  正确地使用可变参数确实可以清理一些垃圾代码。典型的例子是一个带有可变的String参数个数的log方法: 

    Log.log(String code)
    Log.log(String code,  String arg)
    Log.log(String code,  String arg1, String arg2)
    Log.log(String code,  String[] args)

  当讨论可变参数时,比较有趣的是,如果用新的可变参数替换前四个例子,将是兼容的:

Log.log(String code, String... args)

  所有的可变参数都是源兼容的——那就是说,如果重新编译log()方法的所有调用程序,可以直接替换全部的四个方法。然而,如果需要向后的二进制兼容性,那么就需要舍去前三个方法。只有最后那个带一个字符串数组参数的方法等效于可变参数版本,因此可以被可变参数版本替换。

 详情见:http://www.blogjava.net/tangzurui/archive/2008/07/25/217518.html


  类型强制转换


  如果希望调用程序了解应该使用哪种类型的参数,那么应该避免用可变参数进行类型强制转换。看下面这个例子,第一项希望是String,第二项希望是Exception:
    Log.log(Object...  objects) {    String message = (String)objects[0];    if (objects.length > 1) {    Exception e = (Exception)objects[1];    // Do something with the exception    }    }
  方法签名应该如下所示,相应的可变参数分别使用String和Exception声明:

Log.log(String message, Exception e, Object... objects) {...}

  不要使用可变参数破坏类型系统。需要强类型化时才可以使用它。对于这个规则,PrintStream.printf()是一个有趣的例外:它提供类型信息作为自己的第一个参数,以便稍后可以接受那些类型。

  协变返回


  协变返回的基本用法是用于在已知一个实现的返回类型比API更具体的时候避免进行类型强制转换。在下面这个例子中,有一个返回Animal对象的Zoo接口。我们的实现返回一个AnimalImpl对象,但是在JDK 1.5之前,要返回一个Animal对象就必须声明。:
    public interface Zoo  {    public Animal getAnimal();    }  public class ZooImpl  implements Zoo {  public Animal getAnimal(){  return new AnimalImpl();  }  }
  协变返回的使用替换了三个反模式:

 

  • 直接字段访问。为了规避API限制,一些实现把子类直接暴露为字段: ZooImpl._animal
  • 另一种形式是,在知道实现的实际上是特定的子类的情况下,在调用程序中执行向下转换: ((AnimalImpl)ZooImpl.getAnimal()).implMethod();
  • 我看到的最后一种形式是一个具体的方法,该方法用来避免由一个完全不同的签名所引发的问题: ZooImpl._getAnimal();


  这三种模式都有它们的问题和局限性。要么是不够整洁,要么就是暴露了不必要的实现细节。

  协变

  协变返回模式就比较整洁、安全并且易于维护,它也不需要类型强制转换或特定的方法或字段:

public AnimalImpl getAnimal(){
return new AnimalImpl();
}

  使用结果:
ZooImpl.getAnimal().implMethod();

  使用泛型

  
我们将从两个角度来了解泛型:使用泛型和构造泛型。我们不讨论List、Set和Map的显而易见的用法。知道泛型集合是强大的并且应该经常使用就足够了。

  我们将讨论泛型方法的使用以及编译器推断类型的方法。通常这些都不会出问题,但是当出问题时,错误信息会非常令人费解,所以需要了解如何修复这些问题。

posted on 2008-07-21 23:01 梓枫 阅读(249) 评论(0)  编辑  收藏 所属分类: java

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


网站导航: