本文结合《Effective Java》第八章《通用程序设计》和自己的理解及实践,讲解了编写Java代码的一些优秀实践,文章发布于专栏Effective Java,欢迎读者订阅。
在这之前,专栏已经发布了两篇通用原则清单 :
分别介绍了在Java语言中,设计类和接口,以及设计方法的一些通用原则,而在了解完如何设计类接口和方法之后,就要去写它们的具体实现细节,这也就是本文将重点介绍的内容。
这条清单,其实是封装原则的一个衍生,我们都知道,封装是使得一个类的属性不被其他类所访问和篡改,那么在一个代码块里面,我们同样需要让代码块里的各个子代码块的局部变量,不互相影响。
要做到这条原则,有两个小原则:
以下面这两个while循环为例,本意是遍历两个List,但是由于后面的一个while循环,是直接复制上面那个循环然后粘贴的,使用的是上面循环的迭代器,但是由于上面循环的iterator仍在有效范围,因此编译还通过了:
public class TestCycle {
public static void main(String[] args) {
testCycle();
}
private static void testCycle() {
String[] sArr = {"1","2","3"};
List strings = Arrays.asList(sArr);
List strings2 = Arrays.asList(sArr);
Iterator iterator = strings.iterator();
while (iterator.hasNext()) {
String string = (String) iterator.next();
System.out.println(string);
}
Iterator iterator2 = strings2.iterator();
//copy from the while code above, make wrong!
while (iterator.hasNext()) {
String string = (String) iterator.next();
System.out.println(string);
}
}
}
这个例子说明了不控制好局部变量作用域的代价,要修复这个隐藏的缺陷,我们可以使用for循环或者foreach循环:
for(Iterator iterator = strings.iterator(); iterator.hasNext();)
{
String string = (String) iterator.next();
System.out.println(string);
}
从上一条清单的例子,我们知道,for循环比while好,但是它也并非完美,for循环暴露了迭代器和索引变量,会造成一些混乱,比如下面这个双层for循环,在第二层for循环中调用了第一层for循环的迭代器的next方法,破坏了整个循环的顺序:
for (Iterator i = suits.iterator(); i.hasNext(); )
for (Iterator j = ranks.iterator(); j.hasNext(); )
deck.add(new Card(i.next(), j.next()));
代码原意应该是这样:
for (Iterator i = suits.iterator(); i.hasNext(); )
{
Suit suit = i.next();
for (Iterator j = ranks.iterator(); j.hasNext(); )
deck.add(new Card(suit, j.next()));
}
这个例子说明了暴露迭代器的后果,使用for-each可以完美的隐藏迭代器和索引变量:
for (Suit suit : suits)
for (Rank rank : ranks)
deck.add(new Card(suit, rank));
当然,由于隐藏了迭代器和索引,因此在一些需要使用到迭代器或者索引的场合,比如遍历并删除(参考 Java集合遍历删除),那么for-each是不适用的,但是大多数情况下,for-each可以满足我们的需要并且实现十分简洁和高质量的代码。
JDK提供了很多有用的类库,比如随机函数Random.nextInt(int),集合框架,并发工具类库等。
在代码实现中,我们应该优先使用这些提供好的类库,而不是自己去实现。
使用jdk类库的好处在于:
从经济学的角度来看,使用已有类库的功能,是一种成本最小的方法。
经常发现有代码这样写:
private Long mills = ....
大概他是忘了Long还有一个基本类型long吧。
装箱类型和基本类型相比,有两个不同点:
这两点都会给正常的运算带来不必要的麻烦,当然从性能上看,基本类型也比装箱类型快。
所以,除非你是在需要使用装箱类型的场合(比如List
以上,希望对你在实现高质量的Java程序上能有所帮助。