3.3 循环语句

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

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

图3.7 输出图形1
图3.8 输出图形2

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

3.3.1 while循环

  while循环的语法形式如下。

while(循环条件){

    循环代码块

 }
copy

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

图3.9 while循环执行过程

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

class TestWhile1

{

    public static void main(String[] args) 

    {

        int i=0;                                   //声明循环参数

        //循环20次,每次输出20个*

        while(i < 20){                       //循环条件为i<20

            System.out.println("********************");

            i++;                              //循环参数+1

        }

    }

}
copy

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

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

  程序的主界面:

  1.输入数据

  2.输出数据

  3.退出程序

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

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

import java.util.Scanner;

class TestWhile2 

{

    public static void main(String[] args) 

    {

        int userSel = -1;                             //用户选择输入的参数

        while(true){//使用while(true),在单个模块功能执行结束后,重新输出主界面,继续循环

            System.out.println("1. 输入数据");

            System.out.println("2. 输出数据");

            System.out.println("3. 退出程序");

            System.out.print("请选择你的输入(只能输入1、2、3):");

            Scanner input = new Scanner(System.in); 

            userSel = input.nextInt();       //从控制台获取用户输入的选择

            switch(userSel){

                case 1:

                    System.out.println("执行1.输入数据模块");

                    System.out.println("******************");

                    System.out.println("******************");

                    break;

                case 2:

                    System.out.println("执行2.输出数据模块");

                    System.out.println("******************");

                    System.out.println("******************");

                    break;

                case 3:

                    System.out.println("结束程序!");

                    break;

                default:

                    System.out.println("输入数据不正确!");

                    break;

            }

            if (userSel == 3)                    //当用户输入3时,退出while循环,结束程序

            {

                break;

            }

        }

    }

}
copy

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

图3.10 使用while循环输出主界面

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

3.3.2 do…while循环

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

do{

    循环代码块

 }while(循环条件)
copy

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

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


import java.util.Scanner;

class TestWhile3 

{

   public static void main(String[] args) 

   {

       //使用字符串String存储密码,后面课程会详细介绍String类

       String userPass = "";                                //用户输入的密码

       final String PASSWORD = "123456";    //正确密码为123456

       Scanner input = new Scanner(System.in);

       do{

           System.out.print("请输入程序密码:");

           userPass = input.nextLine();           //从控制台获取用户输入的密码

           System.out.println();

           //字符串的equals()方法用于判断两个字符串的值是否相同

       }while(!userPass.equals(PASSWORD));         //密码输入不正确,继续循环,重新输入

       System.out.println("程序密码正确,继续执行!");

   }

}
copy

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

图3.11 do...while循环

3.3.3 for循环

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

for(表达式1;表达式2;表达式3){

    循环代码块

 }
copy

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

class TestFor1 

{

    public static void main(String[] args) 

    {

        int i;//声明循环参数

        //循环20次,每次输出20个*号

        for(i = 0; i < 20; i++ ){

            System.out.println("********************");

        }

    }

}
copy

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

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

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

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

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

图3.12 for循环的执行顺序

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

class TestFor3 

{

    public static void main(String[] args) 

    {

        int sum = 0;//存放和

        //循环参数从1开始,步长为2(奇数和),循环条件为i<=1000

        for(int i = 1;i <= 1000;i = i + 2 ){

            sum = sum + i;

        }

        System.out.println("1~1000之间所有奇数的和为:" + sum);

    }

} 
copy

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

图3.13 计算高薪人员比例及平均底薪

  具体代码如下。

import java.util.Scanner;

class TestFor4 

{

    public static void main(String[] args) 

    {

        int highNum = 0;                                                                          //底薪大于等于6000的Java工程师人数

        int sumBasSalary = 0;                       //高薪人员底薪总和

        Scanner input = new Scanner(System.in);

        for(int i = 1;i <= 10 ; i++ )

        {

            System.out.print("请输入第" + i + "个工程师底薪:");

            int basSalary = input.nextInt();

            if(basSalary >= 6000)

            {

                highNum = highNum + 1;                                //高薪人员计数

                sumBasSalary = sumBasSalary + basSalary;   //高薪人员底薪求和

            }

        }

        System.out.println("10个Java工程师中,高薪人员比例为:" + highNum/10.0*100 + "%");

        System.out.println("高薪人员平均底薪为:" + sumBasSalary/highNum);

    }

}
copy

  细心的读者会发现,该程序在计算过程中有一个缺陷。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中的图形,具体代码如下。

class TestFor2 

{

    public static void main(String[] args) 

    {

        int i,j;                                     //声明循环参数

        for(i = 1;i <= 20;i++){          //循环20次

        for(j = 1;j <= i;j++){    //每次输出当次个*

        System.out.print("*");

        }

            System.out.println();

        }

    }

}
copy

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

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

class TestFor5 

{

//输出1~100间质数

    public static void main(String[] args) 

    {

        int i,j;                                                        //声明循环参数  

        outer:for(i = 2;i < 100;i++){                    //从2开始,逐个递增进行判断

            //Math.sqrt(i)方法是求i的平方根

            for(j = 2;j <= Math.sqrt(i);j++){     //从2开始,逐个递增到外循环的平方根

                if(i%j == 0)               //外循环数除以内循环数,余0则非质数,跳出内循环

                continue outer;             //跳出内循环,跳到outer标识的位置继续循环

            }

                System.out.println(i);                      //否则显示质数

        }

    }

}
copy

3.3.5 跳转语句

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

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