4.3 循环语句
循环语句在程序设计中有什么作用呢?本节将通过一个具体功能(计算数字1连加10次1后的结果)来演示。
【实例4-7】下面先看一段简单的程序段,再来看看使用循环语句编写程序的好处在哪里。
01 ///将x连续加1加10次 02 public class Control4 //定义一个Control4类 03 { 04 public static void main(String[] args) //主方法 05 { //连续自加10次 06 int x=1; //定义整型变量x并赋值 07 x=x+1; 08 x=x+1; 09 x=x+1; 10 x=x+1; 11 x=x+1; 12 x=x+1; 13 x=x+1; 14 x=x+1; 15 x=x+1; 16 x=x+1; 17 System.out.println(x); //输出x最终的结果 18 } 19 }
【代码说明】代码的含义是让变量“x”连续加1共加10次。如果想要实现加1加100次,那要让“x=x+1”这个表达式重复100次。
【运行效果】
11
这样庞大的程序段所要完成的功能,不过是一个很简单的相加功能。为了解决这类问题,程序设计中引入了循环语句。循环语句共有3种常见的形式:for语句、while语句和do…while语句。下面将逐个详细介绍。
4.3.1 for循环语句
让初始值为1的变量“x”连续加1共加10次,可以直接编写10次“x=x+1;”语句,但是如果要加100呢?这时肯定不能编写100次“x=x+1;”语句。为了解决该问题,可以使用for循环语句。
for循环语句的基本结构如下:
for(初始化表达式;判断表达式;递增(递减)表达式) { 执行语句 }
下面详细解释for循环语句中各个子项的意义。
1)初始化表达式:初始化表达式的意义在于定义循环之前变量的值是多少,如果没有这一项,就不知道应该从哪个值开始循环。
2)判断表达式:判断表达式的作用在于规定循环的终点。如果没有判断表达式,那么此循环就成了死循环。
3)递增(递减)表达式:这一项规定每执行一次程序,变量以多少增量或减量进行变化。
注意 一定要注意递增(递减)表达式中可以有多个表达式,它们以逗号间隔,而不是分号。
【实例4-8】使用for语句,来修改上一小节的程序段。
01 public class Control5 //定义一个Control5类 02 { 03 public static void main(String[] args) //主方法 04 { 05 int x; //定义整型变量x 06 int n=10; //定义循环的次数10 07 for( x=1;n>0;n--,x++) //通过循环实现连续加1共10次 08 {System.out.println(x);} //输出x的值 09 } 10 }
【代码说明】上述代码中,第5~8行共4句代码完成了前面程序段里12句代码所实现的事情。
【运行效果】
1 2 3 4 5 6 7 8 9 10
【实例4-9】如果前面的程序段需要连续加1加100次,则参考下面的程序段。
01 public class Control6 //定义一个Control6类 02 { 03 public static void main(String[] args) //主方法 04 { 05 int x; //定义整型变量x 06 int n=100; //定义循环的次数100 07 for(x=1;n>0;n--,x++) //实现循环 08 System.out.println(x); 09 } 10 }
【代码说明】在这个程序段里,使用第5~8行共4句代码可以解决程序段中102句代码所实现的问题,这就是循环语句的优势。
【运行效果】
1 2 3 … 100
其实也可以利用在条件判断语句中提到的流程图来编写程序,在流程图中可以看出程序执行的顺序,如图4-4所示。
图4-4 for循环语句流程图
【实例4-10】下面再看一个九九乘法表的程序段。先来绘制流程图,如图4-5所示。
图4-5 九九乘法表流程图
根据流程图,使用循环语句实现乘法口诀表。
01 ///这是一个二重for循环语句 02 public class Control7 //定义一个Control7类 03 { 04 public static void main(String[] args) //主方法 05 { 06 for(int x=1;x<10;x++) //输出9行 07 { 08 for(int y=1;y<=x;y++) //输出9列 09 { 10 System.out.print(x+"*"+y+"="+(x*y)+"\t"); //输出x*y的结果 11 if(x==y){ //条件判断 12 System.out.println(); //换行 13 } 14 } 15 System.out.println(""); //换行输出空格 16 } 17 } 18 }
【代码说明】第6~16行是外围的for循环,第8~14行是一个嵌入在外围循环中的循环,这样的形式我们称之为嵌套循环。为什么要使用二重循环呢?因为它涉及两个变化的量。在一个程序里,有多少个不同的变量,就要使用多少个for循环,当然也不是非常绝对的。
【运行效果】
1*1=1 2*1=2 2*2=4 3*1=3 3*2=6 3*3=9 4*1=4 4*2=8 4*3=12 4*4=16 5*1=5 5*2=10 5*3=15 5*4=20 5*5=25 6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36 7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49 8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64 9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81
在上面的程序段中,使用了2层嵌套的for语句。其实真正复杂的程序段中,可能会出现4层嵌套的for语句,这要在实践中慢慢体会。
通过上面的内容,可以发现循环流程关键字for的语法比较复杂。为了改变该现象,便出现了关于for循环的另一种语法(增强版for循环),该方式可以简化for循环的书写。
增强版for循环的基本格式如下:
for(type变量名:集合变量名){ }
在上述基本格式中,迭代变量必须在方法体中定义,集合变量除了可以是数组,还可以是实现了Iterable接口的集合类。
下面将通过修改VariableArgument.java类来演示增强版的for,具体内容如下所示:
01 public class VariableArgument { //定义一个VariableArgument类 02 public static int add(int... xs) { //定义一个add方法 03 int sum = 0; //定义整型变量sum并赋值 04 for (int x : xs) { //增强版for循环 05 sum = sum + x; //累加求和并赋值给sum 06 } 07 return sum; //返回变量sum 08 } 09 }
【代码说明】上述代码中通过for(int x:xs)语句代替了for(int x=0;x<xs.length;x++)语句,实现了相应的循序迭代功能。
4.3.2 while循环
在英文中“while”这个词的意思是“当”,而在Java程序设计中,也可以将其理解为“当”。其语法结构如下。
while (条件) { 目的一; 目的二; … }
当满足某种条件,就执行“目的一”、“目的二”等,while语句的循环体在{}中。
【实例4-11】下面看一段程序段,通过分析它,让读者更加清楚while循环语句。
01 //通过判断y是否大于0 02 //如果y大于0的话则将计费次数减1,x加1 03 public class Control8 //定义一个Control8类 04 { 05 public static void main(String[] args) { //主方法 06 int x=0; //定义整型变量x并赋值 07 int y=100; //定义整型变量y并赋值 08 int sum=0; //定义整型变量sum并赋值 09 while(y>0) //while循环 10 { 11 x=x+1; 12 y--; //值自减 13 sum+=x; 14 } 15 System.out.println(sum); //输出和 16 } 17 }
【代码说明】这个程序段是将数字从1一直加到100,条件是只要y大于0,就会执行大括号里的语句。y初始值是100,满足条件,所以执行大括号的表达式。先将x+1赋给x,因为x的初始值是0,所以x从1开始计数,然后,将y自减1,此时y变成了99,将sum加上x赋给sum。此时,执行语句结束了,又会回到小括号的条件,最后再比较y=99是否大于0,如果大于0,再继续执行大括号里的语句。
一旦y自减到小于等于0,则将结束执行大括号里的语句,开始执行大括号外的语句。在上面的程序段中,y就相当于一个计数器。
【运行效果】
5050
同样,在编写while语句时,要先绘制流程图,根据流程图再来编写程序段,整个思路就会很清晰了。下面先看while的流程图,如图4-6所示。
图4-6 while循环语句流程图
其实while语句很简单,根据这个流程图,就可以思路清晰地编写程序段。下面针对上面的程序段来绘制流程图,如图4-7所示。
图4-7 实例4-11的循环流程图
看了这个流程图,会发现按照流程图来编写程序简单多了。为了巩固以上所述,再看一个例子。
【实例4-12】试编写程序实现输出1~100间的整数,并且此整数必须满足:它是3的倍数,但不是5的倍数,也不是9的倍数。针对这个例子,先来绘制一个流程图,如图4-8所示。
图4-8 输出特殊数字的循环流程图
根据流程图,现在来编写程序段。
01 public class Control9 { //定义一个Control9类 02 public static void main(String[] args) { //主方法 03 int x = 1; //定义整型变量x并赋值 04 //判断是否在100以内,并且是3的倍数 05 while (((3 * x > 1) && (3 * x < 100))) { 06 if ((3 * x) % 5 != 0) { //然后再判断这些数是否不是5的倍数 07 if ((3 * x) % 9 != 0) { //最后判断这些数是否不是9的倍数 08 System.out.println(3 * x); //输出3的倍数 09 } 10 } 11 x++; //x自增 12 } 13 } 14 }
【代码说明】第5行是一个循环判断条件,判断是否在100以内,并且是3的倍数。第6行是一个条件语句,判断这些数是否不是5的倍数。第7行也是一个条件语句,判断这些数是否不是9的倍数。
【运行效果】
3 6 12 21 24 33 39 42 48 51 57 66 69 78 84 87 93 96
按照先绘制流程图,后编写程序的步骤,会显得思路更清晰。其实从上面的程序段中,可以总结一点:当由多个条件形成循环条件时,可以选择其中一个作为循环条件,而剩下的条件可以在循环体中作为条件语句。
4.3.3 do…while语句
在学习do…while语句之前,先清楚while语句是如何工作的。while语句是先进行条件判断,再执行大括号内的循环体。do…while语句与while语句不同的是,它先执行大括号内的循环体,再判断条件,如果条件不满足,下次不再执行循环体。也就是说,在判断条件之前,就已经执行大括号内的循环体。
do…while循环语句格式为:
do 执行代码; while(布尔表达式)
【实例4-13】下面先看一个程序段。
01 public class Control10 { //定义一个Control10类 02 public static void main(String[] args) { //主方法 03 int x = 1; //定义整型变量x并赋值 04 do { 05 //首先判断这个数是否是3的倍数,并且是否不是5的倍数 06 if ((3*x)%5!= 0) { 07 if ((3*x)%9!= 0) { //再判断是否不是9的倍数 08 System.out.println(3*x); //输出3的倍数 09 } 10 } 11 x++; //x自加 12 } while (((3*x > 1) && (3*x < 100))); //最后判断是否在100以内 13 } 14 }
【运行效果】
3 6 12 21 24 33 39 42 48 51 57 66 69 78 84 87 93 96
【代码说明】从上面的程序段输出结果可以看出,与使用while语句的输出结果是一样的,为什么会是一样的呢?下面来分析。
当“x=33”时,不会先检验“3*33=99”是否小于100,而是先执行大括号内的循环体。当检测到99是9的倍数时,条件是“false”,于是就会退出条件语句,继续执行“x”自加1表达式,于是“x”变成了34,由于“34*3=102”大于100,所以结束循环体。因此程序执行到“x=32”后就无输出了,最后输出的结果当然和while语句的输出一样。
其实在实际程序开发中,不经常使用do…while循环语句。因为这种语句是先执行循环体再检测条件,所以会有一些危险数据不经检测,就被执行。建议使用while语句或者for循环语句来编写代码。