Java 5 引入了一种更加简洁的 for 语法,可以用于数组和容器(这部分内容会在第 12 章和第 21 章中进一步讲解)。这种语法有时候叫作 “增强的 for”(enhanced for)。大部分文档中直接将其称为 foreach 语法,但 Java 8 里又增加了一个我们经常使用的 forEach() 方法。这样的术语使用起来容易混淆,因此我找了点儿依据,就直接称这种语法为 for-in(比如在 Python 中,实际上的语法就是 for x in sequence,所以这样的称呼是有合理的先例的)。请记住,你可能会在不同的地方看到它的不同叫法。
    for-in 语句会自动为你生成每一项元素,这样你就不需要创建 int 变量来对这个元素构成的序列进行计数。假设有一个 float 数组,你想要选取该数组中的每一个元素:

    1. // control/ForInFloat.java
    2. import java.util.*;
    3. public class ForInFloat {
    4. public static void main(String[] args) {
    5. Random rand = new Random(47);
    6. float[] f = new float[10];
    7. for(int i = 0; i < 10; i++)
    8. f[i] = rand.nextFloat();
    9. for(float x : f)
    10. System.out.println(x);
    11. }
    12. }
    13. /* 输出:
    14. 0.72711575
    15. 0.39982635
    16. 0.5309454
    17. 0.0534122
    18. 0.16020656
    19. 0.57799757
    20. 0.18847865
    21. 0.4170137
    22. 0.51660204
    23. 0.73734957
    24. */

    这个数组是用旧式的 for 循环来填充的,因为在填充时必须按索引访问。下面这行代码中使用的就是 for-in 语法:
    这个数组是用旧式的 for 循环来填充的,因为在填充时必须按索引访问。下面这行代码中使用的就是 for-in 语法:
    for(float x : f) {
    这条语句定义了一个 float 类型的变量 x,然后会将数组 f 里的每一个元素按顺序赋给 x。
    任何返回了数组的方法都可以使用 for-in。例如,String 类有一个 toCharArray() 方法,它返回了一个 char 数组,因此你可以很容易地迭代字符串里的所有字符:

    1. // control/ForInString.java
    2. public class ForInString {
    3. public static void main(String[] args) {
    4. for(char c : "An African Swallow".toCharArray())
    5. System.out.print(c + " ");
    6. }
    7. }
    8. /* 输出:
    9. A n A f r i c a n S w a l l o w
    10. */

    在第 12 章中你会看到,for-in 还可以用于任何 Iterable 对象。
    许多for语句会在一个整数值序列中步进,就像下面这样:
    for(int i = 0; i < 100; i++)
    对于这些语句,for-in 语法不起作用,因为你需要先创建一个 int 数组。为了简化这些任务,我在onjava.Range 包里创建了一个 range() 方法,它会自动生成合适的数组。
    第 7 章会介绍静态引入(static import),不过现在你就可以直接使用这个库,而不需要了解具体的细节。你可以在 import 这一行看到 static import 语法:

    1. // control/ForInInt.java
    2. import static onjava.Range.*;
    3. public class ForInInt {
    4. public static void main(String[] args) {
    5. for(int i : range(10)) // 0~9
    6. System.out.print(i + " ");
    7. System.out.println();
    8. for(int i : range(5, 10)) // 5~9
    9. System.out.print(i + " ");
    10. System.out.println();
    11. for(int i : range(5, 20, 3)) // 5~20,步进3
    12. System.out.print(i + " ");
    13. System.out.println();
    14. for(int i : range(20, 5, -3)) // 倒计时
    15. System.out.print(i + " ");
    16. System.out.println();
    17. }
    18. }
    19. /* 输出:
    20. 0 1 2 3 4 5 6 7 8 9
    21. 5 6 7 8 9
    22. 5 8 11 14 17
    23. 20 17 14 11 8
    24. */

    range() 方法已经被重载(overloaded),重载表示方法名相同但具有不同的参数列表(你很快就会学到重载)。range() 方法的第一种重载形式是从 0 开始产生值,直到范围的上限,但不包括这个上限。第二种形式是从第一个参数值开始产生值,直到比第二个参数值小为止。第三种形式有一个步进值,它每次增加的步幅为该值。在第四种形式中可以倒计时。range() 其实就是一个简化版的生成器,本书稍后会介绍它。
    range() 方法让我们可以在更多的地方使用 for-in 语法,因此可以说提高了可读性。
    注意 System.out.print() 不会生成换行,你可以在一行里输出相关内容。
    for-in 语法不仅方便代码的编写,更重要的是让代码更容易阅读,它表明了你打算做什么(获取数组中的每一个元素),而不是给出如何做的实现细节(“我创建了一个索引,用来选取数组里的每个元素”)。本书更提倡使用 for-in 语法。

    1. // onjava/Range.java
    2. package onjava;
    3. public class Range {
    4. // Produce sequence [start..end) incrementing by step
    5. public static int[] range(int start, int end, int step) {
    6. if(step == 0)
    7. throw new
    8. IllegalArgumentException("Step cannot be zero");
    9. int sz = Math.max(0, step >= 0 ?
    10. (end + step - 1 - start) / step
    11. : (end + step + 1 - start) / step);
    12. int[] result = new int[sz];
    13. for(int i = 0; i < sz; i++)
    14. result[i] = start + (i * step);
    15. return result;
    16. } // Produce a sequence [start..end)
    17. public static int[] range(int start, int end) {
    18. return range(start, end, 1);
    19. }
    20. // Produce a sequence [0..n)
    21. public static int[] range(int n) {
    22. return range(0, n);
    23. }
    24. }