最近这些年买彩票只能去投注站买,早些年,笔者经常是在网上买。在网上买有个功能:追号。就是假如你想一直买同一组号码,直到中大奖为止。你可以设置一个条件,比如中了头奖就不继续买了,如果没有中头奖,下一期继续买同样的号码。对于这样的功能,在程序中可以采用while循环来实现:
代码如下:
while(n<5000000) {
System.out.println("下一期继续买同一组号码");
}
但是事实上,我们先要买第一期,然后才能判断是否中头奖,循环才能继续:
代码如下:
do {
System.out.println("买一组号码");
} while (n < 5000000);
下面我们再用一个示例来解决我们儿子最近学奥数的一个数学问题,计算1+2+3+…+100;
int sum = 0;// 最终结果,初始为0
int add = 1;// 加数,初始为1
while (add <= 100) {
sum = sum + add;
add++;// 加完后,自增1
}
System.out.println(sum);//最终结果是5050
通过上面实例我们知道,当while的条件为真,则执行循环语句。如果这个条件一直为真的话,程序就会进入一个死循环了。因此在实际程序编写的时候,一定要保证这个条件随着程序的运行,会在某一个时刻变为假,避免程序进入死循环。比如上面这个例子变量add会自增,所以一定大于100。
对于上面这个数学问题,我们可以看出来,它的循环次数是固定的,对于这种循环问题,Java还有一种更加简洁的语句来实现,就是for循环。代码可以写成这样:
int sum = 0;// 最终结果,初始为0
for (int add = 1; add <= 100; add++) {
sum += add;
}
System.out.println(sum);// 最终结果是5050
我们可以看到,代码的第2行,把加数add的初始化、循环条件和add的自增都放到一行了,显得更加简洁。它的通用结构如下:
for(表达式1 ; 表达式2 ; 表达式3)
其实对于for循环中括号内,是分成3个部分,每个部分之间用分号(;)隔开。Java允许这3个部分放置任何表达式,并且都是可以省略不写的。示意图如下:
另外,对于在表达式1中声明的变量,它的作用域是整个for循环的循环体。对于在循环语句中定义的变量,作用域只能在循环体{}内。
有的时候,在一个for循环中,会有多个计数器,例如前面追号买彩票的例子,可以设置追号10期,但是有的时候你的账户余额不足了,彩票站不会给你垫钱追号的,代码可以写成这样:
for (int balance = 10, count = 1; balance >= 2 && count <= 10; count++, balance -= 2) {
System.out.println("余额还剩" + balance + "元,购买第" + count + "期彩票");
}
balance:账户余额;count:追号期数
运行结果:
余额还剩10元,购买第1期彩票
余额还剩8元,购买第2期彩票
余额还剩6元,购买第3期彩票
余额还剩4元,购买第4期彩票
余额还剩2元,购买第5期彩票
我们可以看到:
虽然Java的语法规则对for循环的表达式1、表达式2、表达式3的限制非常少,但是笔者不建议编写晦涩难懂的语句,尽量保证代码的可读性。
在上面这个例子中,代码其实写的就有点晦涩,不易阅读。对于余额不足的情况,其实可以认为是中止循环的一个条件。我们可以用break来中止循环,代码可以改写:
int balance = 10;
for (int count = 1; count <= 10; count++) {
System.out.println("余额还剩" + balance + "元,购买第" + count + "期彩票");
balance -= 2;
// 当余额不足2元的时候,中止循环
if (balance < 2) {
break;
}
}
在while中同样可以使用break,我们将上面代码改写成while版本:
int balance = 10;
int count = 1;
while (count <= 10) {
System.out.println("余额还剩" + balance + "元,购买第" + count + "期彩票");
count++;
balance -= 2;
// 当余额不足2元的时候,中止循环
if (balance < 2) {
break;
}
}
这2段代码的运行结果都是:
余额还剩10元,购买第1期彩票
余额还剩8元,购买第2期彩票
余额还剩6元,购买第3期彩票
余额还剩4元,购买第4期彩票
余额还剩2元,购买第5期彩票
break关键字,只能中止当前循环,当有多个循环嵌套使用的时候,有时候想要直接中止最外层循环,对于这种需求,在C++中是使用goto关键字来实现的。我们在学习关键字的时候,发现Java将goto作为保留字了,但是却没有使用它,而是用了另外一种方法来实现。叫做带标签的break语句。
首先我们得想一个多层嵌套的例子,正当我冥思苦想的时候,突然发我儿子床头的一张乘法口诀表:
假如我们用程序打印这张表,可以用到2层嵌套的循环语句。第一层循环打印每一行的所有算式,然后我们把打印每一行的功能也用一个循环来实现即第二层循环。代码如下:
// row是行号,一共需要打印9行
for (int row = 1; row <= 9; row++) {
// column是列号,对于第row行,一共需要打印row列
for (int column = 1; column <= row; column++) {
System.out.print(column + "×" + row + "=" + column * row + " ");
}
System.out.println();// 打印完一行,需要换行
}
运行结果如下:
1×1=1
1×2=2 2×2=4
1×3=3 2×3=6 3×3=9
1×4=4 2×4=8 3×4=12 4×4=16
1×5=5 2×5=10 3×5=15 4×5=20 5×5=25
1×6=6 2×6=12 3×6=18 4×6=24 5×6=30 6×6=36
1×7=7 2×7=14 3×7=21 4×7=28 5×7=35 6×7=42 7×7=49
1×8=8 2×8=16 3×8=24 4×8=32 5×8=40 6×8=48 7×8=56 8×8=64
1×9=9 2×9=18 3×9=27 4×9=36 5×9=45 6×9=54 7×9=63 8×9=72 9×9=81
Perfect!完美的打印出来了。假如我们想在打印到第8行第5列的时候,不想打印了,代码改成下面这样:
// row是行号,一共需要打印9行
for (int row = 1; row <= 9; row++) {
// column是列号,对于第row行,一共需要打印row列
for (int column = 1; column <= row; column++) {
System.out.print(column + "×" + row + "=" + column * row + " ");
if (row == 8 && column == 5) {
break;
}
}
System.out.println();// 打印完一行,需要换行
}
但是这样的结果如下:
1×1=1
1×2=2 2×2=4
1×3=3 2×3=6 3×3=9
1×4=4 2×4=8 3×4=12 4×4=16
1×5=5 2×5=10 3×5=15 4×5=20 5×5=25
1×6=6 2×6=12 3×6=18 4×6=24 5×6=30 6×6=36
1×7=7 2×7=14 3×7=21 4×7=28 5×7=35 6×7=42 7×7=49
1×8=8 2×8=16 3×8=24 4×8=32 5×8=40
1×9=9 2×9=18 3×9=27 4×9=36 5×9=45 6×9=54 7×9=63 8×9=72 9×9=81
虽然第8行第5列之后的没有打印,但是第9行又打印出来了。我们再改成带标签的break。
1 print_row: // 这是一个标签
2 for (int row = 1; row <= 9; row++) {
3 // column是列号,对于第row行,一共需要打印row列
4 for (int column = 1; column <= row; column++) {
5 System.out.print(column + "×" + row + "=" + column * row + " ");
6 if (row == 8 && column == 5) {
7 break print_row;// 中止标签print_row
8 }
9 }
10 System.out.println();// 打印完一行,需要换行
11 }
运行结果:
1×1=1
1×2=2 2×2=4
1×3=3 2×3=6 3×3=9
1×4=4 2×4=8 3×4=12 4×4=16
1×5=5 2×5=10 3×5=15 4×5=20 5×5=25
1×6=6 2×6=12 3×6=18 4×6=24 5×6=30 6×6=36
1×7=7 2×7=14 3×7=21 4×7=28 5×7=35 6×7=42 7×7=49
1×8=8 2×8=16 3×8=24 4×8=32 5×8=40
这一次结果正确。我们在第1行添加一个标签“print_row”,然后在第7行中止该标签。这样做相当于跳转到标签“print_row”标记的代码块的末尾即第11行。需要注意的是,标签后面需要紧跟一个冒号(:)。
在上面打印乘法口诀表的例子,假如我们不想打印第4行和第4列,想想有啥办法吗?我们可以想到,当打印到第4行的时候,直接换一行去打印第5行。当打印到第4列的时候,也跳过,然后去打印第5列。对于这种需求,我们可以用到continue语句。continue的作用就是跳过当前循环体中剩余的部分,回到当前循环的首部。代码如下:
1 for (int row = 1; row <= 9; row++) {
2 /*第4行,打印换行,然后继续打印下一行*/
3 if (row == 4) {
4 System.out.println();
5 continue;
6 }
7 for (int column = 1; column <= row; column++) {
8 /*第4列,打6个空格,然后继续打印下一列*/
9 if (column == 4) {
10 System.out.print(" ");
11 continue;
12 }
13 System.out.print(column + "×" + row + "=" + column * row + " ");
14 }
15 System.out.println();
16 }
运行结果如下:
1×1=1
1×2=2 2×2=4
1×3=3 2×3=6 3×3=9
1×5=5 2×5=10 3×5=15 5×5=25
1×6=6 2×6=12 3×6=18 5×6=30 6×6=36
1×7=7 2×7=14 3×7=21 5×7=35 6×7=42 7×7=49
1×8=8 2×8=16 3×8=24 5×8=40 6×8=48 7×8=56 8×8=64
1×9=9 2×9=18 3×9=27 5×9=45 6×9=54 7×9=63 8×9=72 9×9=81
我们看到,结果第4行和第4列都空出来了。需要注意的是,continue只是跳过当前循环体的剩余部分,如果是for循环,表达式3部分还是会执行的。
continue语句也可以带标签,作用是跳到与标签匹配的循环首部(如果是for循环,则是表达式3)。我们看代码和结果:
print_row:
for (int row = 1; row <= 9; row++) {
for (int column = 1; column <= row; column++) {
/*第4列,则直接打印下一行*/
if (column == 4) {
System.out.println();
continue print_row;
}
System.out.print(column + "×" + row + "=" + column * row + " ");
}
System.out.println();
}
结果:
1×1=1
1×2=2 2×2=4
1×3=3 2×3=6 3×3=9
1×4=4 2×4=8 3×4=12
1×5=5 2×5=10 3×5=15
1×6=6 2×6=12 3×6=18
1×7=7 2×7=14 3×7=21
1×8=8 2×8=16 3×8=24
1×9=9 2×9=18 3×9=27