`
sungang_1120
  • 浏览: 310007 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类

Effective Java学习(通用程序设计)之——将局部变量的作用最小化

阅读更多

      将局部变量作用最小化,可以增强代码的可读性和可维护性,并降低出错的可能性。

较早的程序设计(如C语言)要求局部变量必须再一个代码块的开头进行声明,处于习惯,有些程序员们目前还是继续这样做,这个习惯应该改正,再次提醒:Java允许你在任何可以出现语句的地方声明变量。

 

       要是局部变量作用域最小化,最有力的方法就是在第一次使用它的时候声明。如果变量在使用前声明,这只会造成程序混乱——对于试图理解程序功能的读者来说,这有多了一种只会分散他们的注意力的因素。等到用到该变量的时候,读者可能已经记不起该变量的类型或者初始值了。

 

过早的声明局部变量不仅会使他的作用域过早的扩展,而且结束地也过于晚了。局部变量的作用域从他声明的点开始扩展,一直到外围块的结束处。如果变量是在“使用他的块”之外被声明的,当程序退出该块之后,改变量仍是可见的,如果变量在它的目标使用区域之前或者之后被意外的使用的话,后果将可能是灾难性的。

 

      几乎每个局部变量的声明都应该包含一个初始化的表达式,如果你还没有足够的信息来对一个变量进行有意义的初始化,就应该 推迟这个声明,知道可以初始化为止,这条规则有个例外的情况与try-catch语句有关,如果一个变量被一个方法初始化,而这个方法可能会抛出一个受检异常,该变量就必须在try块的内部被初始化。如果变量的值必须在try块的外部调用的到,她就必须在try之前被声明,但是在try之前,他还不能被“有意义的初始化”。

 

      循环中提供了特殊的机会来将变量的作用域最小化。他们的作用域被限定正好需要的范围之内。因此如果在循环终止之后不再需要这个变量的内容,for循环就优先于while循环。

 

例如:下面是一种遍历集合的首选做法:

Collection<E> c = new ArrayList<E>();
for (E e : c) {
			
}

 在1.5之前,首选的做法如下:

for (Iterator<E> i = c.iterator();i.hasNext();) {
         i.next();
}

 为了弄清楚这个for循环为什么比while更好,请考虑下面代码片段,它包含两个while循环,以及一个bug:

Iterator<E> i = c.iterator();
	while(i.hasNext()){
		i.next();
}
		
		
Iterator<E> i2 = c2.iterator();
	while (i.hasNext()) {
		i2.next();
}

       第二个循环中,本来是要初始化一个新的变量i2,但是却是用了旧的变量i,遗憾的是,这时i仍然还在有效范围之内,结果代码仍然可以通过编译,运行的时候也不不会抛出异常,但是他所做的事情确实错误的,,第二个循环并没在c2上迭代,而是立即终止,造成c2为null的假象,因为这个程序的错误是悄然发生的所以可能在很长时间内都不会被发现。

 

       如果类似的错误发生在前面任何一种for循环中,结果代码就根本不能通过编译,在第二个循环开始之前,第一个循环的元素变量已经不再他的作用域范围之内了:

for(Iterator<E> i = c.iterator(); i.hasNext();){
	i.next();
}
		
for(Iterator<E> i2 = c2.iterator(); i.hasNext();){
	i2.next();
}

       而且,如果使用for循环,犯这种错误的可能性就会大大减少,因为有必要在两个循环中使用不同的变量名,循环是完全独立的,所以重用元素变量的名称不会有任何危害,实际上,这也是很流行的做法。

 

使用for循环与使用while循环相比之下还有另一个优势:更简短,从而增强了可读性,

下面是另外一种对局部变量的作用域进行最小化的循环做法:

for(int i = 0, n = expensiveComputation; i < n; i++){
   
}

       关于这种做法要关注的一点是,它具有两个循环变量:i和n两者具有完全相同的作用域。第二个变量n被调用来保存第一个变量的极限值,从而避免在每次迭代中执行冗余计算的开销。通常,如果循环测试中涉及方法调用,它可以保证每次迭代中都会返回同样的结果,就应该使用这种做法。

 

      最后一种“将局部变量的作用域最小化”的方法是使方法小而集中。如果把两个操作合并到同一方法中,与其中一个操作相关的局部变量就有可能会出现在执行另一个操作的代码范围之内。为了防止这种情况出现,只要把这个方法分成两个,每个方法个执行一个操作。

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics