4.3.3 for循环

4.3.3 for循环

for循环是更加简洁的循环语句,大部分情况下,for循环可以代替while循环、do while循环

for循环的语法格式

for循环的基本语法格式如下:

1
2
3
for ([初始化语句]; [循环条件]; [迭代语句]){
循环体
}

for循环执行流程

程序执行for循环时,先执行循环的初始化语句,初始化语句只在循环开始前执行次。每次执行循环体之前,先计算循环条件的值,如果循环条件返回true,则执行循环体,循环体执行结束后,执行循环迭代语句

因此,对于for循环而言,循环条件总比循环体要多执行一次,因为最后一次执行循环条件返回false,将不再执行循环体。

for循环的continue无法结束 循环迭代语句

值得指出的是,for循环的循环迭代语句并没有与循环体放在一起,因此即使在执行循环体时遇到continue语句结束本次循环,循环迭代语句依旧会执行

while循环do while循环的continue 会结束 循环迭代语句

for循环和whiledo while循环不一样:由于whiledo while循环的循环迭代语句紧跟着循环体,因此如果循环体不能完全执行,如使用continue语句来结束本次循环,则循环迭代语句不会被执行。

for循环的循环迭代语句并没有与循环体放在一起,因此不管是否使用continue语句来结束本次循环,for选好的循环迭代语句一样会获得执行
与前面循环类似的是,如果循环体只有一行语句,那么循环体的花括号可以省略。

程序示例

下面使用for循环代替前面的while循环,代码如下。

1
2
3
4
5
6
7
8
9
public class ForTest {
public static void main(String[] args) {
// 循环的初始化条件,循环条件,循环迭代语句都在下面一行
for (int count = 0; count < 10; count++) {
System.out.println(count);
}
System.out.println("循环结束!");
}
}

for循环可以多个初始化语句 使用复杂的循环条件

在上面的循环语句中,for循环的初始化语句只有一个,循环条件也只是一个简单的boolean表达式。实际上,for循环允许同时指定多个初始化语句,循环条件也可以是一个包含逻辑运算符的表达式。例如如下程序:

1
2
3
4
5
6
7
8
9
public class ForTest2 {
public static void main(String[] args) {
// 同时定义了三个初始化变量,使用&&来组合多个boolean表达式
for (int b = 0, s = 0, p = 0; b < 10 && s < 4 && p < 10; p++) {
System.out.println(b++);
System.out.println(++s + p);
}
}
}

上面代码中初始化变量有三个,但是只能有一个声明语句,因此如果需要在初始化表达式中声明多个变量,那么这些变量应该具有相同的数据类型

建议不要在循环体内修改循环变量

初学者使用for循环时也容易犯一个错误,他们以为只要在for后的圆括号内控制了循环迭代语句就万无一失,但实际情况则不是这样的。例如下面的程序

1
2
3
4
5
6
7
8
9
10
11
public class ForErrorTest {
public static void main(String[] args) {
// 循环的初始化条件,循环条件,循环迭代语句都在下面一行
for (int count = 0; count < 10; count++) {
System.out.println(count);
// 再次修改了循环变量
count *= 0.1;
}
System.out.println("循环结束!");
}
}

在上面的for循环中,表面上看起来控制了count变量的自加,表达式count<10有变成false的时候。但实际上程序中在循环体内修改了count变量的值,并且把这个变量的值乘以了0.1。这会导致count的值永远都不能超过10,因此上面程序也是一个死循环。

建议不要在循环体内修改循环变量(也叫循环计数器)的值,否则会増加程序出错的可能性。万一程序真的需要访问、修改循环变量的值,建议重新定义一个临时变量,先将循环变量的值赋给临时变量,然后对临时变量的值进行修改。

for循环的初始化语句 循环条件 迭代语句都可以省略

for循环的圆括号中只有两个分号是必需的,初始化语句、循环条件、迭代语句部分都是可以省略的
如果省略了for循环的循环条件,则这个循环条件默认为true,将会产生一个死循环。例如下面程序。

1
2
3
4
5
6
7
8
public class DeadForTest {
public static void main(String[] args) {
// 省略了for循环三个部分,循环条件将一直为true
for (;;) {
System.out.println("xxxxx");
}
}
}

while循环转for循环

使用for循环时,还可以把初始化条件定义在循环体之外,把循环迭代语句放在循环体内,这种做法就非常类似于前面的while循环了。下面的程序再次使用for循环来代替前面的whie循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ForInsteadWhile {
public static void main(String[] args) {
// 把for循环的初始化条件提出来独立定义
int count = 0;
// for循环里只放循环条件
for (; count < 10;) {
System.out.println(count);
// 把循环迭代部分放在循环体之后定义
count++;
}
System.out.println("循环结束!");
// 此处将还可以访问count变量
}
}

上面程序的执行过程和前面的WhileTest.java程序的执行过程完全相同。因为把for循环的循环迭代部分放在循环体之后,则会岀现与while循环类似的情形,如果循环体部分使用continue语句来结束本次循环,将会导致循环迭代语句得不到执行

如何在for循环外访问循环变量的值

扩大循环变量的作用域

for循环的初始化语句放在循环之前定义还有一个作用:可以扩大初始化语句中所定义变量的作用域。在for循环里定义的变量,其作用域仅在该循环内有效,for循环终止以后,这些变量将不可被访问。如果需要在for循环以外的地方使用这些变量的值,就可以采用上面的做法。

定义额外的变量来保存循环变量的值

除此之外,还有种做法也可以满足这种要求:额外定义一个变量来保存这个循环变量的值。例如下面代码片段:

1
2
3
4
5
6
7
8
9
int tmp =0;
//′循环的初始化条件、循环条件、循环迭代语句都在下面一行
for (int i =0 ;i < 10 ; 1++){
System.out.println(i);
tmp =i;
}
//使用tmp来保存循环变量i的值
System.out.println("循环结束!");
//此处还可通过tmp变量来访问i变量的值

相比前面的代码,通常更愿意选择这种解决方案。使用一个变量tmp来保存循环变量i的值,使得程序更加清晰,变量i和变量tmp的责任更加清晰。反之,如果采用前一种方法,则变量i的作用域被扩大了,功能也被扩大了。
作用域扩大的后果是:如果该方法还有另一个循环也需要定义循环变量,则不能再次使用i作为循环变量

建议使用i,j,k作为循环变量

选择循环变量时,习惯选择i、j、k来作为循环变量。