通用编程:循环、库的使用与精确计算
立即解锁
发布时间: 2025-08-18 00:29:03 阅读量: 15 订阅数: 21 


Effective Java:编写高效Java代码的最佳实践
# 通用编程:循环、库的使用与精确计算
## 1. 优先使用 for - each 循环而非传统 for 循环
在编程中,循环是常用的控制结构。传统的 for 循环用于遍历集合和数组,示例代码如下:
```java
// Not the best way to iterate over a collection!
for (Iterator<Element> i = c.iterator(); i.hasNext(); ) {
Element e = i.next();
... // Do something with e
}
// Not the best way to iterate over an array!
for (int i = 0; i < a.length; i++) {
... // Do something with a[i]
}
```
然而,这种传统的 for 循环存在一些问题:
- **代码冗余**:迭代器和索引变量增加了代码的复杂度,实际上我们只需要元素本身。
- **易出错**:迭代器和索引变量在循环中多次出现,容易使用错误的变量,且编译器不一定能捕获这些问题。
- **类型依赖**:集合和数组的循环方式不同,在切换容器类型时会带来一些麻烦。
而 for - each 循环(官方称为“增强 for 语句”)解决了这些问题。它隐藏了迭代器或索引变量,使代码更简洁,并且适用于集合和数组,方便切换容器类型。示例代码如下:
```java
// The preferred idiom for iterating over collections and arrays
for (Element e : elements) {
... // Do something with e
}
```
当看到冒号(:)时,可以理解为“在”,即“对于 elements 中的每个元素 e”。使用 for - each 循环不会有性能损失,生成的代码与手动编写的代码基本相同。
在嵌套迭代时,for - each 循环的优势更加明显。下面是一个常见的嵌套迭代错误示例:
```java
// Can you spot the bug?
enum Suit { CLUB, DIAMOND, HEART, SPADE }
enum Rank { ACE, DEUCE, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT,
NINE, TEN, JACK, QUEEN, KING }
...
static Collection<Suit> suits = Arrays.asList(Suit.values());
static Collection<Rank> ranks = Arrays.asList(Rank.values());
List<Card> deck = new ArrayList<>();
for (Iterator<Suit> i = suits.iterator(); i.hasNext(); )
for (Iterator<Rank> j = ranks.iterator(); j.hasNext(); )
deck.add(new Card(i.next(), j.next()));
```
这个代码的问题在于,外部集合(suits)的迭代器的 next 方法调用次数过多。它应该在外部循环中调用,使得每个花色调用一次,但实际上在内部循环中调用,导致每张牌调用一次。当花色用完后,循环会抛出 NoSuchElementException。
如果使用嵌套的 for - each 循环,问题就会消失,代码也会更加简洁:
```java
// 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 循环:
- **破坏性过滤**:如果需要遍历集合并移除选定的元素,需要使用显式的迭代器来调用其 remove 方法。在 Java 8 中,可以使用 Collection 的 removeIf 方法来避免显式遍历。
- **转换操作**:如果需要遍历列表或数组并替换部分或全部元素的值,需要使用列表迭代器或数组索引来替换元素的值。
- **并行迭代**:如果需要并行遍历多个集合,需要显式控制迭代器或索引变量,以便所有迭代器或索引变量能够同步前进。
for - each 循环不仅可以遍历集合和数组,还可以遍历实现了 Iterable 接口的任何对象。该接口的定义如下:
```java
public interface Iterable<E> {
// Returns an iterator over the elements in this iterable
Iterator<E> iterator();
}
```
如果要从头实现 Iterable 接口会有点棘手,但如果编写的类型表示一组元素,即使不实现 Collection 接口,也应该考虑实现 Iterable 接口,这样用户就可以使用 for - each 循环遍历该类型。
### 1.1 总结
for - each 循环在清晰度、灵活性和防止错误方面比传统 for 循环具有明显优势,且没有性能损失。在可能的情况下,应优先使用 for - each 循环。
### 1.2 流程图
```mermaid
graph TD;
A[开始] --> B{是否需要遍历集合或数组};
B -- 是 --> C{是否为破坏性过滤、转换操作或并行迭代};
C -- 否 --> D[使用 for - each 循环];
C -- 是 --> E[使用传统 for 循环];
B -- 否 --> F[结束];
D --> F;
E --> F;
```
## 2. 了解并使用库
在编程中,有许多常见的任务可以通过使用标准库来更高效地完成。例如
0
0
复制全文
相关推荐









