【EFJava】通用程序设计

Num1:for-each循环优先于传统的for循环

java1.5版本发布之前的做法:

1
2
3
for(int i=0;i<a.length;i++){
doSomething(a[i]);
}

java1.5发行版本中引入的for-each循环,通过完全隐藏迭代器或索引变量,避免了混乱和出错的可能。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
enum Suit {
CLUB, DIAMOND, HEART, SPADE
}

enum Rank {
ACE, DEUCE, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING
}

class Card {
final Suit suit;
final Rank rank;

Card(Suit suit, Rank rank) {
this.suit = suit;
this.rank = rank;
}
}

public class NestedIteration {
public static void main(String[] args) {
Collection<Suit> suits = Arrays.asList(Suit.values());
Collection<Rank> ranks = Arrays.asList(Rank.values());

List<Card> deck = new ArrayList<Card>();
for (Iterator<Suit> i = suits.iterator(); i.hasNext();)
for (Iterator<Rank> j = ranks.iterator(); j.hasNext();)
deck.add(new Card(i.next(), j.next()));

// Preferred idiom for nested iteration on collections and arrays
// for (Suit suit : suits)
// for (Rank rank : ranks)
// deck.add(new Card(suit, rank));
}
}

总之,for-each循环在简洁性和预防Bug方面有着传统的for循环无法比拟的优势,并且没有性能损失。应该尽可能地使用for-each循环。遗憾的是,有三种常见的情况无法使用for-each循环:

  • 过滤:如果需要遍历集合,并删除选定的元素,就需要使用显式的迭代器,以便可以调用它的remove方法。
  • 转换:如果需要遍历列表或者数组,并取代它部分或者全部的元素值,就需要列表迭代器或者数组索引,以便设定元素的值。
  • 平行迭代:如果需要并行地遍历多个集合,就需要显式地控制迭代器或者索引变量,以便所有迭代器或者索引变量都可以得到同步前移。

Num2:如果需要精确的答案,请避免使用float和double

floatdouble类型尤其不适合用于货币计算。

Num3:基本类型优先于装箱基本类型

自动装箱减少了使用装箱基本类型的繁琐性,但是并没有减少它的风险。

Num4:如果其他类型更适合,则尽量避免使用字符串

  • 字符串不适合代替其他的值类型
  • 字符串不适合代替枚举类型
  • 字符串不适合代替聚集类型
  • 字符串也不适合代替能力表

Num5:当心字符串连接的性能

字符串连接操作符(+)是把多个字符串合并一个字符串的便利途径。为连接n个字符串而重复地使用字符串连接操作符,需要n的平方级的时间。

不要使用字符串连接操作符来合并多个字符串,除非性能无关紧要。相反,应该使用StringBuilderappend方法。

Num6:通过接口引用对象

一般来讲,应该优先使用接口而不是类来引用对象。

  • 如果有合适的接口类型存在,那么对于参数、返回值、变量或域来说,就都应该使用接口类型进行声明。
  • 如果没有合适的接口存在,完全可以用类而不是接口来引用对象。

如果你养成了用接口的作为类型的习惯,你的程序将会更加灵活。

,