第三章 Java程序控制结构

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

教学提示:前面几章介绍的Java程序只能按照语句的书写顺序依次执行,还不具备选择功能和循环功能。

本章将介绍Java语言的三种程序结构:顺序结构、选择结构和循环结构。

在三种结构中,顺序结构比较简单,而选择结构和循环结构是由Java语言的控制语句实现的。

Java语言的控制语句分为选择语句、循环语句和跳转语句。

教学目标:掌握Java语言三种程序控制结构,能灵活运用控制语句编写程序。

3.1顺序结构
顺序结构是一种按照从上到下逐步执行程序的结构,中间没有判断和跳转语句,是最简单的程序结构,为了加深对顺序结构程序的认识,下面我们演示一个程序。

【例3-1】输入一个数,求其平方根。

设计思路:完成这个任务需要以下3个操作步骤:输入数据;计算其平方根;显示结果。

代码:j301.java
import java.io.*;
public class j301
{
public static void main(String arg[]) throws IOException
{
int x;
double y;
String str; //声明字符串类
BufferedReader buf; //声明缓冲数据流类
System.out.print("请输入一个数:");
buf=new BufferedReader(new InputStreamReader(System.in));
str=buf.readLine();
x=Integer.parseInt(str);
y=Math.sqrt(x); //求平方根
System.out.println(x+"的平方根为:"+y); //显示计算结果
}
}
运行结果如图3-1所示:
29
30
图3-1 例3-1程序的运行结果
程序的第1行是import语句,引入java.io包中的所有类,Java语言中处理输入输出
的类都是在该包中。

由于程序中是使用缓冲字符输入流类(BufferedReader)和字符输入流类(InputStreamReader),因此必须使用import语句引入它们。

程序中声明和创建缓冲字符输入流类的具体对象buf。

创建类对象实例化通过以下方式实现:
类名对象名=new 构造函数(参数);
BufferedReader buf=new BufferedReader(new InputStreamReader (System.in));
缓冲字符输入流类的构造函数的参数是定义字符输入流类的一个具体对象System.in,System.in表示从键盘输入。

通过这种方式把键盘输入的字符串读入到缓冲区。

程序中调用BufferedReader 类中的方法readLine()读取缓冲区中的一行字符串,读取的字符串赋给字符串变量str。

由于readLine()会抛出异常处理(IOException),因此在程序main()方法的方法头部加入了throws IOException,表示main()方法把IOException异常抛出,交给JVM 处理。

这些详细内容将在本书后面进行详细说明。

程序中Integer.parseInt(str)的作用是把数字字符串转换成整型数据,因为Java从命令行输入的数据都当作字符串,必须把它转换成整型数据后才能赋值给整型变量。

程序中Math.sqrt(x)用的是数学类的求平方根方法sqrt,其返回的类型为double,所以y定义为double类型。

3.2选择结构
程序设计时,经常需要根据条件表达式或变量的不
同状态选择不同的路径,解决这一类问题,通常使用选
择结构。

常见的选择结构有三种:单分支选择结构、双
分支选择结构和多分支选择结构。

3.2.1单分支选择结构
单分支选择结构可以根据指定表达式的当前值,选
择是否执行指定的操作。

单分支语句由简单的if语句组
成,该语句的一般形式为:
if(表达式)
图3-2 简单if语句流程

子句;
语句说明:
1.if是Java语言的关键字,表示if语句的开始。

2.if后边表达式必须为合法的逻辑表达式,即表达式的值必须是一个布尔值,不能用数值代替。

3.在表达式为真时执行子句的操作。

子句可由一条或多条语句组成,如果子句由一条以上的语句组成,必须用花括号把这一组语句括起来。

【例3-2】输入一个数,求其平方根。

设计思路:例3-1已经初步解决了这个问题,本题只需在例3-1算法的基础上,增加一个简单的分支结构,实现对输入非负数进行求平方根的操作。

代码:程序j302.java
import java.io.*;
public class j302
{
public static void main(String arg[]) throws IOException
{
int x;
double y;
String str;
BufferedReader buf;
System.out.print("请输入一个数:");
buf=new BufferedReader(new InputStreamReader(System.in));
str=buf.readLine();
x=Integer.parseInt(str);
if (x>=0)
{
y=Math.sqrt(x);
System.out.println(x+"的平方根为:"+y);
}
}
}
运行结果如下图:
图3-3 例3-2程序的运行结果
31
32 在程序中if 后面的花括号不能省,如果没有花括号,系统默认if 后面的第一条语句是if 的内部语句。

例如:在有花括号时如输入负数则没有结果显示,去掉if 语句中的花括号程序也能运行并有结果输出,但输出的结果不正确。

3.2.2双分支选择结构
双分支选择结构可以根据指定表达式的当前值选择执行两个程序分支中的一个分支。

包含else 的if 语句可以组成双分支选择结构,该语句的一般形式为:
if (表达式) 子句1; else 子句2; 语句说明:
1. 表达式的值为真时,执行子句1;表达式值为假时,执行子句2。

2. 如果if 与else 之间的子句1包含多于一条语句的内部语句,必须用花括号把内部语句括起来,
失去了花括号,编译程序时系统将报错;如果else 后
面的子句2包含多于一条的内部语句,也必须用花括号把这些内部语句括起来,丢了花括号,系统默认else 后面的第一条语句是else 的内部语句,运行程序时也将出现错误。

【例3-3】输入一个数,求其平方根。

设计思路:本题在例3-2的基础上将单分支选择结构换成双分支选择结构,对输入非负数的情况,求其平方根;对负数的情况,给出一个错误信息。

代码:j303.java import java.io.*;
public class j303 {
public static void main(String arg[]) throws IOException {
int x;
double y;
String str; BufferedReader buf;
System.out.print("请输入一个数:");
buf=new BufferedReader(new InputStreamReader(System.in)); str=buf.readLine(); x=Integer.parseInt(str); if (x>=0) {
图3-4 if else 语句
y=Math.sqrt(x);
System.out.println(x+"的平方根为:"+y);
}
else
System.out.println("输入错误!");
}
}
3-5:
程序运行结果如图
3.2.3多分支选择结构
在应用程序中,不仅会遇到单分支或双分支选择的问题,还会遇到多分支的问题。

例如,输入一个成绩判断它的等级是优、良、中、及格、还是不及格。

对于像这样的问题就可以用多分支选择结构解决。

在Java语言中使用嵌套的if语句或switch语句实现多分支选择结构的功能。

1.嵌套的if语句
在if或else语句中有包含一个或多个if语句称为if语句的嵌套。

形式如下:
(1)在if子句、else子句中嵌套if语句:
if(表达式1)
if(表达式2)子句1;
else 子句2;
else
if(表达式3)子句3;
else 子句4;
执行过程为:如果表达式1为真,则判断表达式2,如果表达式2为真,执行子句1,否则执行语句2;如果表达式1为假,接着判断表达式3,如果表达式3为真,执行语句3,否则执行语句4。

(2)if-else if形式
if-else if是一种特殊的if嵌套形式,它使程序层次清晰,易于理解,在多分支结构的程序中经常使用这种形式。

形式如下:
if(表达式1)
子句1;
else if(表达式2)
33
子句2;
……
else
子句n;
执行过程:语句从上向下执行,当if语句表达式1为真时,只执行子句1,如果表达式1为假,则跳过子句1,再判断表达式2的值,并根据表达式2的值选择是否执行子句2。

即从上到下逐一判断if后面表达式的值,当某一表达式值为真时,就执行与该语句相关的子句,其它子句就不执行;如果所有表达式值都为假,则执行最后else后面的子句,如没有else,则直接执行if嵌套后面的语句。

【例3-4】编写程序,输入一个成绩,输出成绩的等级。

等级划分标准:85分以上为优,75~84为良,60~74为中,60分以下为不及格。

设计思路:首先需要输入学生的成绩,其次根据学生的成绩判断等级。

由于等级的分界点是85、75、60。

我们先用if处理85分以上的和85分以下的两种情况;当程序流入85分以下分支时,再用if语句处理75分以上和75分以下的两中情况;依次类推直到小于60分以下。

代码:j304.java
import java.io.*;
public class j304
{
public static void main(String arg[]) throws IOException
{
int x;
String str;
BufferedReader buf;
System.out.print("请输入学生成绩(0-100)之间:");
buf=new BufferedReader(new InputStreamReader(System.in));
str=buf.readLine();
x=Integer.parseInt(str);
if(x>=85)
System.out.println("成绩优秀!");
else if(x>=75)
System.out.println("成绩良好!");
else if(x>60)
System.out.println("成绩及格!");
else
System.out.println("成绩不及格!");
}
}
34
程序中应用多层嵌套if-else if语句,该语句可以根据输入的成绩,选择执行4种等级之一。

运行结果如输入75,运行结果如图3-6:
图3-6例3-4运行结果
2.I f与else的匹配
在使用嵌套的if语句时,要特别注意if与else的匹配问题。

如果程序中有多个if和else,当没有花括号指定匹配关系时,系统默认else与它前面最近的且没有与其它else配对的if 配对。

例如下面这种有嵌套的if语句中,else是与第二个if配对。

if(表达式1)
if(表达式2)
子句1;
else
子句2;
如果在有嵌套的if语句中加了花括号,由于花括号限定了嵌套的if语句是处于外层if语句的内部语句,所以else与第一个if配对,如下:
if(表达式1)
{
if(表达式2)
子句1
}
else
子句2
3.s witch语句
如上介绍的if语句是判定语句,是从两个语句块中选择一块语句执行,只能出现两个分支,对于多分支情况,其只能用嵌套的if语句的处理。

而switch语句是多分支选择语句,在某些情况下,用switch语句代替嵌套的if语句处理多分支问题,可以简化程序,使程序结构更加清晰明了。

switch语句的一般形式如下:
switch(表达式)
{
case 值1:子句1;break;
case 值2:子句2;break;
……
35
case 值n:子句n;break;
default:子句m;
}
语句说明:
(1)switch是关键字,表示switch语句的开始。

(2)switch语句中的表达式的值只能是整型或字符型。

(3)case后面的值1、值2……值n必须是整型或字符型常量,各个case后面的常量值不能相同。

(4)switch语句的功能是把表达式返回的值与每个case子句中的值比较,如果匹配成功,则执行该case后面的子句。

(5)case后面的子句和if后面的子句相似,可以是一条语句,也可以是多条语句。

不同的是当子句为多条语句时,不用花括号。

(6)break语句的作用是执行完一个case分支后,使程序跳出switch语句,即终止switch语句的执行。

如果某个子句后不使用break语句,则继续执行下一个case语句,直到遇到break语句,或遇到标志switch语句结束的花括号。

(7)最后的default语句的作用是当表达式的值与任何一个case语句中的值都不匹配时执行default;如省略default,则直接退出switch语句。

【例3-5】输入成绩的英文等级:A、B、C、D,输出对应的中文等级:优秀、良好、及格、不及格。

设计思路:首先需要输入学生的成绩的英文等级,其次根据输入的字符,选择显示不同的中文等级。

根据题意,程序分支应该有5个,分别显示优秀、良好、及格、不及格和输入错误。

根据以上程序分析,代码如下。

代码:j305.java
import java.io.*;
public class j305
{
public static void main(String arg[]) throws IOException
{
char ch;
System.out.print("请输入英文等级(A,B,C,D):");
//接受从键盘上输入的一个数据把它转换成一个字符
ch=(char)System.in.read();
switch(ch)
{
case 'A':
case 'a': System.out.println("成绩优秀!"); break;
case 'B':
case 'b': System.out.println("成绩良好!");break;
36
case 'C':
case 'c': System.out.println("成绩及格!");break;
case 'D':
case 'd': System.out.println("成绩不及格!");break;
default:System.out.println("输入错误!");
}
}
}
运行结果如图3-7所示:
图3-7 例3-5运行的结果
程序中System.in.read()作用是从系统标准输入即键盘读入一个整型数据,经强制类型转换成字符型赋给字符变量ch。

由于方法read会抛出输入输出异常(IOException),因此在程序main()方法的方法头增加了throws IOException。

程序中应用switch分支语句,在分支语句中都是两个case标号对应一个子句,意味着输入小写a、b、c、d与大写A、B、C、D运行结果等效。

4.i f语句与switch语句
if语句与switch语句都可以用于处理选择结构的程序,但它们的使用环境不同:单分支结构选择结构一般使用if语句,双分支结构一般使用if-else语句,多分支结构一般使用嵌套的if语句和switch语句,对于需要计算多个表达式值,并根据计算结果执行某个操作,一般用if-else if 语句;对于只需要计算一个表达式值,并根据这个表达式的结果选择执行某个操作,一般用switch语句。

注意:if语句的表达式必须是逻辑表达式,其值是布尔类型;
switch语句的表达式必须是整型或字符型,其值是整型或字符型。

3.3循环结构
程序设计时,有时需要重复执行程序中一个或多个语句,这时就需要用循环结构。

循环结构是由循环语句来实现的,Java语句的循环结构共有三种:while语句、do……while语句和for语句。

它们的执行流程如图3-8所示:
37
38
3.3.1 while 语句
while 语句的一般格式如下: while (条件表达式) 循环体; 语句说明:
1. while 是Java 语言的关键字,表示while 语句的开始。

2. while 语句的执行:每次先判断条件表达式的值为真或为假,如为真则执行循环体,如为假退出循环。

3. 条件表达式指定循环的条件,所以表达式的值必需是布尔类型。

4. 循环体可以是一条语句,也可以是多条语句。

当多条语句是需用花括号括起。

5. while 语句是先判定条件,在执行循环体。

【例3-6】用户从键盘输入字符,直到输入‘#’程序结束。

要求:输入字符后显示输入字符的ASCII 值并最终统计出输入字符的个数。

设计思路:对于这个例题,要求输入多个字符,很显然要用到循环,在循环体内需要解决三个问题:一是如何输入字符;二是如何将输入的字符转换成对应的ASCII ;三是如何统计字符的个数。

对于第一个问题,我们在例3-5中介绍过如何接受从键盘上输入数据的语句,即系统提供的in 对象的read 方法;对于第二个问题只需把输入的字符转换成整型,并把转换后的值输出;对于第三个问题,我们需要设置一个整型变量count ,使count 的初值是0,每循环一次count 加1,当循环结束时,count 就可以统计出字符的个数。

代码:j306.java import java.io.*; public class j306 {
(a )while …do 语(b )do …while 语句 图3-8 三种循环流程
public static void main(String arg[]) throws IOException
{
char ch;
int count=0; //对count初始化
System.out.println("请输入一个字符,以’#‘结束输入:");
ch=(char)System.in.read(); //对ch赋值,接受第一个字符
while(ch!='#') //判断输入的字符是否为'#'
{
//输出字符对应的ASCII值
System.out.println("字符"+ch+"的ASCII值为:"+(int)ch);
System.in.skip(2); //跳过回车键
count=count+1; //字符个数增1
ch=(char)System.in.read();
}
System.out.println("输入的字符共"+count);
}
}
运行结果如图3-9所示:
图3-9例3-6运行结果
3.3.2 do…while语句
do-while 语句的一般格式如下:
do
循环体
while(条件表达式);
语句说明:
1.do-while语句的执行:先执行循环体,再判断循环条件,如为真则重复执行循环体,如为假退出循环。

2.do-while语句的循环体如果包含一条语句以上,必须用花括号括起来。

3.do-while循环的循环体至少执行一次。

【例3-7】对例3-6进行改编,用do-while语句实现。

设计思路:本题的解决方法在例3-6进行了说明。

注意两个程序的区别。

代码:j307.java
import java.io.*;
public class j307
{
public static void main(String arg[]) throws IOException
{
char ch;
int count=0;
System.out.println("请输入字符,以’#‘结束输入:");
do
{
ch=(char)System.in.read();
System.out.println("字符"+ch+"的ASCII值为:"+(int)ch);
System.in.skip(2);
count=count+1;
} while(ch!='#') ;
System.out.println("输入的字符共:"+count);
}
}
例3-6与例3-7程序的区别是:当输入‘#’时,例3-6中的while语句是先判断条件,再执行循环体,所以字符‘#’输入的时候,循环体内的语句不再执行,计数器不累加。

结果如图3-7;例3-7中的do-while语句是先执行循环体,再判定条件,所以能显示#的ASCII 并计数器的值累加为1。

运行结果如图3-10:
图3-10 例3-7运行结果
3.3.3 for语句
1.for语句的一般格式为:
for(表达式1;表达式2;表达式3)
循环体;
语句说明:
(1)表达式1:for循环的初始化部分,它用来设置循环变量的初值,在整个循环过程中只执行一次;表达式2:其值类型必须为布尔类型,作为判断循环执行的条件;表达式3:控制循环变量的变化。

(2)执行过程:
①计算表达式1的值;
②再判断表达式2的值是否为真,为真执行③,为假执行步骤⑤;
③执行循环体
④计算表达式3的值,并转去执行步骤②;
⑤结束循环。

(3)表达式之间用分号分隔。

(4)循环体可以是一条语句,也可以多条语句,当多条语句时用花括号括起来。

(5)上述三个表达式中的每个允许并列多个表达式,之间用逗号隔开。

也允许省略上述的三个表达式,但分号不能省略。

【例3-8】计算1+2+3+…+100的值
设计思路:完成这个任务需要解决两个问题:一是如何提供所需的加数,二是如何累加求和。

加数从1到100,所以只需在循环结构中定义一个整型变量i,初值为1,每循环一次使i加1,当i到100时结束循环。

求和需要定义一个整型变量,且初值为0。

循环每执行一次sum的值加i直到i的值到100结束。

代码如下:
代码:j308.java
public class j308
{
public static void main(String arg[])
{
int i,sum; //定义变量
/**方法1*/
sum=0; //给存放累加和的变量赋初值0
for (i=1;i<=100;i++) //求累加和的循环开始
sum=sum+i; //求累加和
System.out.println("1+2+...+100="+sum);
/**方法2*/
for (sum=0,i=1;i<=100;sum=sum+i,i++); //循环语句
System.out.println("1+2+...+100="+sum);
/**方法3*/
i=1;sum=0; //赋初值
for (;;)
{
sum=sum+i; //求累加和
if (i>=100) break; //退出循环条件
i++; //加数自加
}
System.out.println("1+2+...+100="+sum);
}
}
在方法2中for语句中的表达式1,表达式3都是有两个简单表达式组合起来的逗号表达式。

逗号表达式按从左到右的顺序对每个简单表达式求解,其中最右边的表达式的值是整个表达式的值。

例如对逗号表达式a=3,b= 3*a,则系统先计算i=5,再计算b=3*a,并且b=18就是逗号表达式的值。

另外程序第12行for括号外紧跟一个分号,表示for语句的循环体是一个空语句,如果遗漏了这个分号,系统默认下一行语句为for语句的循环体。

方法3是对for语句中表达式进行省略的例子,但在编程一般不省略表达式。

运行结果如图3-11:
图3-11 例3-8例题结果
2.循环嵌套
如果要完成一件工作,有时需要进行重复的操作,并且某些操作本身又需要进行重复的操作,这些问题常常需要在循环语句中嵌套循环语句来解决。

【例3-9】求1-1000之间的所有完全数。

设计思路:完全数是等于其所有因子和的数。

因子包括1但不包括其本身,如6=1*2*3,则1,2,3都为6的因子,并且6=1+2+3,所以6就是完全数。

首先设定数据i是给定数据区间内的任意数即i从1取到1000;其次让i被1到小于i 中的所有数除,若i能被j(设变量j为从1取到i-1)整除,则让变量sum(因子和,设定初值为0)加j,并让j=j+1;若不能则让j=j+1;直到判定j等于i时,i不再被j除,表示此时的sum是变量i的所有因子的和。

然后判定sum的值是否等于i的值,如相等则i是完全数。

所以例3-9需要两层循环,外层循环判定一个数i是不是完全数,内层循环用来求出数i 的因子和。

代码如下:
代码:j309.java
public class j309
{
public static void main(String arg[])
{
int i,j,sum; //定义变量
for(i=1;i<1000;i++)
{
sum=0;
for(j=1;j<i;j++)
{
if(i%j==0) sum=sum+j; //因子累加
}
if(sum==i) //判定是否为完全数
System.out.print(i+"\t");
}
System.out.println();
}
}
运行结果如图3-12所示:
图3-12 例3-9程序运行结果
3.3.4循环跳转语句
Java中可以使用break和continue两个循环跳转语句进一步控制循环。

这两个语句的一般格式如下:
⏹break [label];用来从switch语句、循环语句中跳出。

⏹countinue [lable]:跳过循环体的剩余语句,开始执行下一次循环。

这两个语句都可以带标签也可以不带标签,标签是出现在一条语句之前的标识符,标签后面要跟上一个冒号(:),定义格式如下:
label:statement;
下面对这两种语句进行分别介绍。

1.b reak语句
break语句有两种形式:不带标签和带标签。

在switch语句中,我们使用的是不带标签的break语句,那时它的作用是跳出switch语句。

在循环语句中不带标号的break语句的作用是最内层的循环语句,而带标号的break语句的作用是从标签指定的语句块中跳出。

【例3-10】在一维数组中找出指定的数。

设计思路:首先设置一个数组如array和要查找的指定数据search,并设置数组中的元素和指定数据的值;然后用循环访问数组中的元素,如数组中的元素与指定的数据相同则结束循环。

代码:j310.java
public class j310
{
public static void main(String arg[])
{
int[] array={10,78,57,89,37,64,5,23,45,76};//定义一维数组
int find=5; //指定数据初始化
int i=0; //数组下标初始化
boolean flag=false; //搜索标记初始化
for(;i<array.length;i++) //查找数组中的所有元素
{
if (array[i]==find) //如果找到数据
{
flag=true;
break; //终止循环
}
}
if (flag==true)
System.out.println("Found "+find+" at index:"+i);
else
System.out.println("not found!");
}
}运行结果如图3-13所示:
图3-13 例3-10运行结果
【例3-11】在二维数组中找出指定的数。

设计思路:设计步骤与例3-10相同,但二维数组的下标分为行标和列标,所以在对二维数组进行访问时,应使用循环嵌套,外层访问行标,内层访问列标。

当找到指定数据时,结束的是整个循环嵌套,而不是内层循环。

代码:j311.java
public class j311
{
public static void main(String arg[])
{
int[][] array={{10,78,57,89,37},{64,5,23,45,76}};//二维数组初始化
int find=5; //指定数据初始化
int i=0,j=0; //二维数组行标列标初始化
boolean flag=false;
found:
for(;i<array.length;i++) //对二维数据每个元素访问的开始
{
for(j=0;j<array.length;j++)
if (array[i][j]==find)
{
flag=true;
break found; //终止外层循环
}
}
if (flag==true)
System.out.println("Found "+find+" at index:"+i+","+j);
else
System.out.println("not found!");
}
}
运行结果如图3-14
图3-14 例3-11运行结果
2.c ontinue语句
continue语句必须用于循环结构中,它也有两种形式即不带标签和带标签。

不带标签的continue语句的作用是结束最内层所执行的当前循环,并开始执行最内层的下一次循环;带标签的continue语句的作用是结束当前循环,并去执行标签所处的循环。

【例3-12】找出2-100之间的所有素数。

设计思路:首先设置一个变量i(从2到100内的任意数据),再让i被j(j从2到i-1的任意值)除,若i能被j之中的任何一个数整除,则提前改变i的值进入下一次循环。

代码:j312.java
public class j312
{
public static void main(String arg[])
{
int i,j;
loop:
for(i=2;i<=100;i++)
{
for(j=2;j<i;j++)
if((i%j)==0) continue loop;
if(j>=i)
System.out.print(i+"\t");
}
}
}运行结果如图3-15所示:
图3-15 例3-12显示结果。

相关文档
最新文档