3.3 循环语句

  为什么要使用循环语句呢?

  如果需要在控制台输出如图3.7和图3.8所示的两组图形,如何输出呢?

3.3 循环语句 - 图1
图3.7 输出图形1

3.3 循环语句 - 图2
图3.8 输出图形2

用之前学过的知识,可以输出这些图形,逐行输出每行的内容即可。但是,如果要输出100、1000行,怎么办?接下来,使用循环语句解决这个问题。

3.3.1 while循环

  while循环的语法形式如下。

  1. while(循环条件){
  2. 循环代码块
  3. }

  其语义是:如果循环条件的值为true,则执行循环代码块,否则跳出循环,其执行过程如图3.9所示。

3.3 循环语句 - 图3
图3.9 while循环执行过程

  使用while循环,输出图3.7中的图形,代码如下。

  1. class TestWhile1
  2. {
  3. public static void main(String[] args)
  4. {
  5. int i=0; //声明循环参数
  6. //循环20次,每次输出20个*
  7. while(i < 20){ //循环条件为i<20
  8. System.out.println("********************");
  9. i++; //循环参数+1
  10. }
  11. }
  12. }

  在使用while循环以及下面介绍的do…while循环时,必须要注意,在循环体中要改变循环条件中的参数(例如本例中的i++)或者有其他跳出循环的语句,这样才能跳出循环,否则就会出现死循环。

  下面使用while循环再完成一个案例,这个案例的需求如下。

  程序的主界面:

  1.输入数据

  2.输出数据

  3.退出程序

  请选择你的输入(只能输入1、2、3):

  当用户输入1时,执行模块1的功能,执行完毕之后,继续输出主界面;当用户输入2时,执行模块2的功能,执行完毕之后,继续输出主界面;当用户输入3时,则退出程序。具体代码如下所示,在“蓝桥系统”中也会使用类似的代码结构,需要注意。

  1. import java.util.Scanner;
  2. class TestWhile2
  3. {
  4. public static void main(String[] args)
  5. {
  6. int userSel = -1; //用户选择输入的参数
  7. while(true){//使用while(true),在单个模块功能执行结束后,重新输出主界面,继续循环
  8. System.out.println("1. 输入数据");
  9. System.out.println("2. 输出数据");
  10. System.out.println("3. 退出程序");
  11. System.out.print("请选择你的输入(只能输入1、2、3):");
  12. Scanner input = new Scanner(System.in);
  13. userSel = input.nextInt(); //从控制台获取用户输入的选择
  14. switch(userSel){
  15. case 1:
  16. System.out.println("执行1.输入数据模块");
  17. System.out.println("******************");
  18. System.out.println("******************");
  19. break;
  20. case 2:
  21. System.out.println("执行2.输出数据模块");
  22. System.out.println("******************");
  23. System.out.println("******************");
  24. break;
  25. case 3:
  26. System.out.println("结束程序!");
  27. break;
  28. default:
  29. System.out.println("输入数据不正确!");
  30. break;
  31. }
  32. if (userSel == 3) //当用户输入3时,退出while循环,结束程序
  33. {
  34. break;
  35. }
  36. }
  37. }
  38. }

  程序运行结果如图3.10所示。

3.3 循环语句 - 图4
图3.10 使用while循环输出主界面

  如图3.10所示,当用户输入2时,执行case 2后面的代码并跳出switch语句,之后再通过if语句判断用户输入的是否是3,如果是3,则跳出while循环,结束程序,如果不是3,则继续执行while循环,输出主界面。

3.3.2 do…while循环

  do…while循环的语法形式如下。

  1. do{
  2. 循环代码块
  3. }while(循环条件);

  do…while循环和while循环类似,不同点在于do…while循环以do开头,先执行循环代码块,然后再判断循环条件,如果循环条件满足,则继续循环。由此可见,do…while循环中的循环代码块至少会被执行一次。

  下面完成一个案例,这个案例的需求是让用户输入正确的程序密码之后,才可以执行下面的代码,否则继续让用户输入,直到输入正确为止,具体代码实现如下。

  1. import java.util.Scanner;
  2. class TestWhile3
  3. {
  4. public static void main(String[] args)
  5. {
  6. //使用字符串String存储密码,后面课程会详细介绍String类
  7. String userPass = ""; //用户输入的密码
  8. final String PASSWORD = "123456"; //正确密码为123456
  9. Scanner input = new Scanner(System.in);
  10. do{
  11. System.out.print("请输入程序密码:");
  12. userPass = input.nextLine(); //从控制台获取用户输入的密码
  13. System.out.println();
  14. //字符串的equals()方法用于判断两个字符串的值是否相同
  15. }while(!userPass.equals(PASSWORD)); //密码输入不正确,继续循环,重新输入
  16. System.out.println("程序密码正确,继续执行!");
  17. }
  18. }

  程序运行结果如图3.11所示。

3.3 循环语句 - 图5
图3.11 do…while循环

3.3.3 for循环

  上面介绍了while循环和do…while循环,其实程序员在编程过程中,使用最多的循环结构是for循环。for循环主要的特点是结构清晰,易于理解,在解决能确定循环次数的问题时,首选for循环。for循环的语法形式如下。

  1. for(表达式1;表达式2;表达式3){
  2. 循环代码块
  3. }

  前面通过while循环完成了图3.7中图形的输出,下面使用for循环完成同样的功能,具体代码如下。

  1. class TestFor1
  2. {
  3. public static void main(String[] args)
  4. {
  5. int i;//声明循环参数
  6. //循环20次,每次输出20个*号
  7. for(i = 0; i < 20; i++ ){
  8. System.out.println("********************");
  9. }
  10. }
  11. }

  for循环的重点在于其3个表达式,其中:

  • 表达式1通常是赋值语句,一般是循环语句的初始部分,为循环参数赋初值。表达式1可以省略,但需要在for语句前给循环参数先赋值。

  • 表达式 2 通常是条件语句,即为循环条件,当该条件满足时,进入循环,不满足则跳出循环。表达式2也可以省略,即不判断循环条件,也就形成了死循环。

  • 表达式 3 通常也是赋值语句,属于循环结构的迭代部分,当一次循环代码块执行完毕以后,程序执行表达式3,然后再去判断表达式2的循环条件是否满足。表达式3通常用来更改循环参数的值。表达式3也可以省略,如果省略,通常需要在循环代码块中添加修改循环参数的语句。

  综上,可以发现for循环的执行顺序如图3.12所示。

3.3 循环语句 - 图6
图3.12 for循环的执行顺序

  如果需要求出1~1000之间所有奇数的和,实现代码如下。

  1. class TestFor3
  2. {
  3. public static void main(String[] args)
  4. {
  5. int sum = 0;//存放和
  6. //循环参数从1开始,步长为2(奇数和),循环条件为i<=1000
  7. for(int i = 1;i <= 1000;i = i + 2 ){
  8. sum = sum + i;
  9. }
  10. System.out.println("1~1000之间所有奇数的和为:" + sum);
  11. }
  12. }

  假设“蓝桥系统”中可以存放10个Java工程师信息,现在需要分别输入这10个Java工程师的底薪,并计算出底薪大于等于6000的高薪人员比例以及这些高薪人员的底薪平均值,程序运行结果如图3.13所示。

3.3 循环语句 - 图7
图3.13 计算高薪人员比例及平均底薪

  具体代码如下。

  1. import java.util.Scanner;
  2. class TestFor4
  3. {
  4. public static void main(String[] args)
  5. {
  6. int highNum = 0; //底薪大于等于6000的Java工程师人数
  7. int sumBasSalary = 0; //高薪人员底薪总和
  8. Scanner input = new Scanner(System.in);
  9. for(int i = 1;i <= 10 ; i++ )
  10. {
  11. System.out.print("请输入第" + i + "个工程师底薪:");
  12. int basSalary = input.nextInt();
  13. if(basSalary >= 6000)
  14. {
  15. highNum = highNum + 1; //高薪人员计数
  16. sumBasSalary = sumBasSalary + basSalary; //高薪人员底薪求和
  17. }
  18. }
  19. System.out.println("10个Java工程师中,高薪人员比例为:" + highNum/10.0*100 + "%");
  20. System.out.println("高薪人员平均底薪为:" + sumBasSalary/highNum);
  21. }
  22. }

  细心的读者会发现,该程序在计算过程中有一个缺陷。sumBasSalary是一个int型的整数,存放的是高薪人员底薪之和,highNum也是一个int型的整数,存放的是高薪人员人数,两个int型的数相除,结果还是int型的数,会丢失小数点后面的精度。

3.3.4 双重for循环

  前面的课程在介绍if语句的时候,提到了嵌套的if语句。同样,在for循环里,也可以嵌套for循环,如果只嵌套一次,就构成双重for循环。

  图3.7需要在控制台输出20行,每行输出20个,采用for循环20次,每次输出20个,即输出图3.7中的图形。图3.8也是需要在控制台输出20行,不过每行输出的的个数不同,第i行输出i个,所以采用单次循环无法解决这个问题。接下来,通过双重for循环,输出图3.8中的图形,具体代码如下。

  1. class TestFor2
  2. {
  3. public static void main(String[] args)
  4. {
  5. int i,j; //声明循环参数
  6. for(i = 1;i <= 20;i++){ //循环20次
  7. for(j = 1;j <= i;j++){ //每次输出当次个*
  8. System.out.print("*");
  9. }
  10. System.out.println();
  11. }
  12. }
  13. }

  双重for循环的重点在于,内循环的循环条件往往和外循环的循环参数有关,例如本例中内循环的循环条件为j <= i,其中i是外循环的循环参数。

  下面使用双重for循环再完成一个案例,这个案例的需求很简单,输出1至100之间的质数,具体实现代码如下,程序逻辑参考代码中的注释,其中continue语句后面会详细介绍。

  1. class TestFor5
  2. {
  3. //输出1~100间质数
  4. public static void main(String[] args)
  5. {
  6. int i,j; //声明循环参数
  7. outer:for(i = 2;i < 100;i++){ //从2开始,逐个递增进行判断
  8. //Math.sqrt(i)方法是求i的平方根
  9. for(j = 2;j <= Math.sqrt(i);j++){ //从2开始,逐个递增到外循环的平方根
  10. if(i%j == 0) //外循环数除以内循环数,余0则非质数,跳出内循环
  11. continue outer; //跳出内循环,跳到outer标识的位置继续循环
  12. }
  13. System.out.println(i); //否则显示质数
  14. }
  15. }
  16. }

3.3.5 跳转语句

  在介绍switch语句的时候,首次接触了break语句,其作用是跳出switch代码块,执行switch语句后面的代码。在介绍双重for循环时,用到了continue语句,continue语句的主要作用为跳出当次循环,继续执行下一次循环。其中break、continue以及后面要学到的return语句,都是让程序从一部分跳转到另一部分,习惯上都称为跳转语句。

  在循环体内,break语句和continue语句的区别在于:使用break语句是跳出循环执行循环之后的语句,而continue语句是中止本次循环继续执行下一次循环。在企业面试的时候,这个问题经常被问到,务必掌握。大家通过前面的案例以及后面的上机任务,能体会到两者的区别,掌握其具体使用方法,这里不再详细举例。