您的位置:首页 > 其它

将局部变量的作用域最小化

2016-08-31 09:21 344 查看

将局部变量的作用域最小化

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

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

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

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

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

  循环中提供了特殊的机会来将变量的作用域最小化。(无论是传统的还是for-each形式的)for循环,都允许声明循环变量,它们的总用域被限定在正好需要的范围之内。(这个范围包含循环体,以及循环体之前的初始化、测试、更新部分。)因此,如果循环终止之后不再需要循环变量的内容,for循环优先于while循环。

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

// Preferred idiom for iterating over a collection
for(Element e : c){
doSomething(e);
}

  在Java 1.5发行版之前,首选的做法如下:

// No for-each loop or generice befor release 1.5
for(Interator i = c.iterator(); i.hasNext(); ){
doSomething(e);
}

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

Iterator<Element> i = c.iterator();
while(i.hasNext()){
doSomething(i.next());
}
...
Interator<Element> i2 = c2.iterator();
while(i.hasNext()){//Bug
doSomething(i2.next());
}

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

  如果类似的“剪切-粘贴”错误发生在前面任何一宗for循环中,结果代码就根本不会编译。在第二个循环开始之前,第一个循环元素(或者迭代器)变量已经不再它的作用域的范围之内了:

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

  而且,如果使用for循环,犯这种“剪切-粘贴”错误的可能性会大大降低,因为通常没有必要在两个循环中使用不同的变量名。循环是完全独立的,所以重用元素(或者迭代器)变量的名称不会有任何危害。实际上,这也是很流行的做法。

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

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

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

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

  最后一种“将局部变量的作用域最小化”的方法是使方法小而集中。如果把两个操作合并到一个方法中,与其中的一个相关的局部变量就有可能会出现执行另一个操作的代码范围之内。为了防止这种事情的发生,只要把这个方法分成两个,每个方法各执行一个操作。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: