2.3 流程控制
处理数据时,需要分若干步骤逐步地进行处理。
不同的数据处理过程不同。即使相同的数据,在不同的情况下,处理过程也可能不同。所以,要对数据的处理过程进行控制。
控制数据处理的过程可以通过流程控制语句来实现。
流程控制语句包括顺序控制语句、选择控制语句和循环控制语句。
2.3.1 顺序控制语句
顺序控制语句
顺序控制语句是按程序员所写程序中的语句顺序由前往后顺序执行。
【例2.5】给定三角形的三边长(一定能组成三角形),计算三角形的周长和面积。
计算三角形的面积可以用海伦公式。
【代码】
import java.util.Scanner;
public class Example2_05
{
public static void main(String args[])
{
Scanner reader=new Scanner(System.in);
double a,b,c;
double area,perim,s;
System.out.print("输入三边的长度:");
a=reader.next Double();//读入三边长度
b=reader.next Double();
c=reader.next Double();
perim=a+b+c;
s=perim/2;
area=Math.sqrt(s*(s-a)*(s-b)*(s-c));
System.out.println("三角形的三边长是:"+a+","+b+","+c);
System.out.printf("三角形的面积:%.2f,",area);
System.out.printf("三角形的周长:%.2f\n",perim);
}
}
程序运行结果如图2-6所示。
图2-6 例2.5程序运行结果
计算机在执行程序时,绝对不会从中间的某一条语句甚至最后一条语句开始执行,执行完成后再从第一条语句执行,而只能从第一条语句开始按照程序员所写的语句的顺序逐条语句执行。
2.3.2 选择控制语句
利用选择控制语句,可以使程序有条件地执行某些语句,或不执行某些语句,而不必按照语句顺序执行程序。使用选择控制语句,可以提高程序的通用性。
Java中选择控制语句包括if语句和switch语句。
1.if选择语句
if选择语句
可以通过if语句给出条件,只有满足条件的语句才能被执行。
if语句可以分为简单的if语句、if-else语句和if-else if-else语句。if语句中还可以有if语句,称为if语句的嵌套。
(1)简单的if语句
简单的if语句可以带有一个条件和子句。根据子句是一条语句还是多条语句,if语句分为两种语法形式如下:
“条件表达式”可以是一个逻辑常量(true或false),也可以是一个逻辑变量,多数情况下是一个关系或逻辑表达式。“if”之后是它的子句,子句可以是一条语句,也可以是多条语句。如果是一条语句,使用“形式1”;如果是多条语句作为子句,则使用“形式2”,加“{}”可以使子句成为一个复合语句。当然,“形式1”的子句也可以加“{}”,但通常情况下都不加。作为if子句的多条语句又可称为复合语句。
if语句的执行过程是,当执行if语句时,先计算“条件表达式”的值。如果值为“true”,则执行下面的子句,接着再继续往下执行下面的语句;如果值为“false”,则越过(不执行)子句执行子句下面的语句。if语句的执行过程可用图2-7表示。
图2-7 if语句的执行过程
【例2.6】给定两个正整数,找出这两个正整数中的大数。
要找两个数中的大数,就需要判断哪一个数大,可以使用if语句判断。
【代码】
import java.util.Scanner;
public class Example2_06
{
public static void main(String args[])
{
int a,b,max;
Scanner reader=new Scanner(System.in);
System.out.print("输入两个整型数:");
a=reader.next Int();
b=reader.next Int();
max=a;//先假设最大数是a
if(a<b)//再判断,条件还可写成“max<b”
max=b;
System.out.println("大数是:"+max);
}
}
程序运行结果如图2-8所示。
图2-8 例2.6运行结果
也可以将子句和语句写在一行:
但是一般都分行写以提高程序的清晰性和可读性。
【例2.7】重写例2.5,当给定的三边长能构成三角形时才计算三角形的面积。
例2.5的程序不算是一个完整的程序。现在的程序要先判断三边能构成三角形才计算三角形的面积。现在利用if语句进行判断,可以写出完整的程序。
【代码】
import java.util.Scanner;
public class Example2_07
{
public static void main(String args[])
{
Scanner reader=new Scanner(System.in);
double a,b,c;
double area,perim,s;
System.out.print("输入三边的长度:");
a=reader.next Double();//读入三边长度
b=reader.next Double();
c=reader.next Double();
if(a+b>c && a+c>b && b+c>a)//任意两边之和大于第三边
{
perim=a+b+c;
s=perim/2;
area=Math.sqrt(s*(s-a)*(s-b)*(s-c));
System.out.println("三角形的三边长是:"+a+","+b+","+c);
System.out.printf("三角形的面积:%.2f,",area);
System.out.printf("三角形的周长:%.2f\n",perim);
return;//执行此语句,程序结束,下面的语句不再执行
}
System.out.println("所给的三边不能构成三角形!");
}
}
程序运行结果如图2-9所示。
图2-9 例2.7运行结果
上例中的计算过程也可以写成下面的形式:
if(a+b<=c || a+c<=b || b+c<=a)//任意两边之和不大于第三边
{
System.out.println("所给的三边不能构成三角形!");
return;//执行此语句,程序结束,下面的语句不再执行
}
//开始计算
perim=a+b+c;
s=perim/2;
area=Math.sqrt(s*(s-a)*(s-b)*(s-c));
System.out.println("三角形的三边长是:"+a+","+b+","+c);
System.out.printf("三角形的面积:%.2f,",area);
System.out.printf("三角形的周长:%.2f\n",perim);
(2)if-else语句
if-else语句
if-else语句可以实现两个分支。它的语法形式:
if(条件表达式)
语句1
else
语句2
“条件表达式”与简单的if语句相同。“语句1”和“语句2”可以是一条语句,也可以是多条语句。如果是多条语句,需要用“{}”括起来形成一个复合语句,如简单的if语句中的形式2。
if-else语句的执行过程是,当执行if-else语句时,先计算“条件表达式”的值。如果该值为“true”,则执行“语句1”,否则执行“语句2”。图2-10表示的是if-else语句的执行过程。
图2-10 if-else语句的执行过程
【例2.8】用if-else语句重写例2.7。
【代码】
import java.util.Scanner;
public class Example2_08
{
public static void main(String args[])
{
Scanner reader=new Scanner(System.in);
double a,b,c;
double area,perim,s;
System.out.print("输入三边的长度:");
a=reader.next Double();//读入三边长度
b=reader.next Double();
c=reader.next Double();
if(a+b>c && a+c>b && b+c>a)//任意两边之和大于第三边
{
perim=a+b+c;
s=perim/2;
area=Math.sqrt(s*(s-a)*(s-b)*(s-c));
System.out.println("三角形的三边长是:"+a+","+b+","+c);
System.out.printf("三角形的面积:%.2f,",area);
System.out.printf("三角形的周长:%.2f\n",perim);
//return;这条语句不需要了!
}
else
System.out.println("所给的三边不能构成三角形!");
}
}
例2.6中的语句:
max=a;//先假设最大数是a
if(a<b)//再判断,条件还可写成“max<b”
max=b;
可以写成:
if(a>b)//再判断,条件还可写成“max<b”
max=a;
else
max=b;
还可以用条件运算符计算:
max=a>b? a:b;
(3)if语句的嵌套
if语句的嵌套
如果if或else的子句还包含if语句,则将所包含的if语句称为if语句的嵌套。
用嵌套的if语句可以实现更复杂的判断,或者将复杂的判断分成几个简单的判断。
if语句的嵌套没有固定形式,根据问题的需要进行判断。可以写出如下几种形式:
对于形式1,第1个if语句嵌套了第2个if语句,当“条件1”和“条件2”都为“true”时,会执行“语句”。形式1可以用一个if语句实现:
if(条件1 &&条件2)
语句
对于形式2,当条件1为真并且条件11也为真时执行语句1。如果条件1为真,但条件11为假,则计算条件2,如果条件2为真,则执行语句2;条件1为真但条件2为假,则不执行语句2。如果条件1为假,语句1和语句2都不能被执行,而直接执行语句2下面的语句。
对于形式3,当条件1为真并且条件11也为真时执行语句1。如果条件1为真而条件11为假,则执行语句2。如果条件1为假,语句1和语句2都不能被执行,直接执行语句2下面的语句。
对于形式4,当条件1为真并且条件11也为真时执行语句1。如果条件1为假而条件2为真,则执行语句2。
形式1和形式3有相似之处,形式2和形式4有相似之处,请读者分析一下它们的区别。
if语句嵌套时要注意if和else的对应关系,一般地,else总是和它上面离其最近的if对应的。但可以通过加“{}”改变对应关系,如形式4就是在形式2的基础上加了“{}”而改变了对应关系。
【例2.9】根据学生的百分成绩给出成绩等级。90分以上为优秀,80分以上为良好,70分以上为中等,60分以上为及格,低于60分为不及格。
本例可以用嵌套的if语句实现。
【代码】
import java.util.Scanner;
public class Example2_09
{
public static void main(String args[])
{
int score;
String grade;
Scanner reader=new Scanner(System.in);
System.out.print("输入成绩:");
score=reader.next Int();
if(score>=90)
grade="优秀";
else
if(score>=80)
grade="良好";
else
if(score>=70)
grade="中等";
else
if(score>=60)
grade="及格";
else
grade="不及格";
System.out.println("成绩等级为:"+grade);
}
}
使用嵌套的if语句时,嵌套的层数不宜过多。如果嵌套的层数过多,会降低程序的可读性。一般嵌套层数不应超过3层。
(4)if-else if-else语句
if-elseif-else语句
if-else if-else可以实现更多情况的判断。它的语句形式:
if(条件表达式1)
语句1
else if(条件表达式2)
语句2
…
else if(条件表达式n)
语句n
else
语句n+1
“条件表达式……”必须是关系或逻辑表达式,“语句”的写法同if-else,最后的“else”可以没有。
if-else if-else语句的执行过程是,先计算“条件表达式1”的值,如果该值为“true”,则执行“语句1”,否则计算“条件表达式2”的值;如果“条件表达式2”的值为“true”,则执行“语句2”;……;如果前n个表达式的值都为“false”,则执行“语句n”。它的执行过程如图2-11所示。
图2-11 if-else if-else语句的执行过程
【例2.10】用if-else if-else语句改写例2.9。
【代码】
import java.util.Scanner;
public class Example2_10
{
public static void main(String args[])
{
int score;
String grade;
Scanner reader=new Scanner(System.in);
System.out.print("输入成绩:");
score=reader.next Int();
if(score>=90)
grade="优秀";
else if(score>=80)
grade="良好";
else if(score>=70)
grade="中等";
else if(score>=60)
grade="及格";
else
grade="不及格";
System.out.println("成绩等级为:"+grade);
}
}
同样的问题,用if-else if-else语句进行判断处理,程序的清晰性更好。实际上,if-else if-else语句就是嵌套的if语句,只不过在书写形式上做了改变。
【例2.11】闰年问题——根据给定的年份判断该年是否是闰年。
一个年份是否是闰年,只要满足下面条件中的一个条件即可。如果年份能被4整除,但不能被100整除;或者,能被400整除。
可以用几种方法写出这个程序。
【代码】
public class Example2_11
{
public static void main(String args[])
{
boolean leap;
int year=2005;
//方法1:if-else语句,最好的方法
if ((year%4==0 && year%100!=0) || (year%400==0))
System.out.println(year+"年是闰年");
else
System.out.println(year+"年不是闰年");
// 方法2,if-else if-else语句
year=2008;
if (year%4!=0)
leap=false;
else if (year%100!=0)
leap=true;//满足第1个条件
else if(year%400!=0)
leap=false;//两个条件都不满足
else
leap=true;//满足第2个条件
if (leap==true)
System.out.println(year+"年是闰年");
else
System.out.println(year+"年不是闰年");
// 方法3,嵌套的if语句
year=2040;
if (year%4==0)
if (year%100!=0)
leap=true;
else
if (year%400==0)
leap=true;
else
leap=false;
else
leap=false;
if (leap==true)
System.out.println(year+"年是闰年");
else
System.out.println(year+"年不是闰年");
}
}
在本例中,方法1将判断闰年的条件直接表达出来,简单明了,有良好的清晰性。而方法2的判断过于复杂,方法3的判断复杂并且嵌套过多。
读者在编写程序时应以程序简洁、清晰为原则。
程序运行结果如图2-12所示。
图2-12 例2.11运行结果
2.switch选择语句
switch选择语句
switch语句也用于选择判断。
当判断条件较多时,用if或嵌套的if语句会降低程序的可读性,这时可用switch语句实现多重选择判断。
switch语句的语法形式:
switch(表达式)
{
case 常量1:
语句组1;
case 常量2:
语句组2;
……
case 常量n:
语句组n;
default:
语句组n+1;
}
其中,“表达式”的值和“常量”的数据类型必须是byte、short、char、int、枚举或String,“常量”值必须互不相同。若干个常量没有顺序要求,但一般按常量的升序或降序书写。“default”也可以写在最前面,或中间某个位置,“default”也可以没有。
switch语句的执行过程是,先计算“表达式”的值,表达式的值与哪一个“常量”相同(匹配)则转到哪个“语句组”并执行该“语句组”,执行之后,再接着执行下面的语句组,直到之后的所有语句组执行完毕,整个switch语句结束。
例如,“表达式”的值和“常量1”相等,则程序转向“语句组1”并执行,执行完毕后,再接着执行“语句组2”“语句组3”、……、“语句组n+1”;如果“表达式”的值和“常量2”相等,则程序从“语句组2”开始执行下面的所有语句;如果“表达式”的值和所有的“常量”都不相等,则执行“语句组n+1”,如果没有“default”,则switch不执行任何语句,程序结束。
switch语句的执行过程如图2-13所示。
图2-13 switch语句的执行过程
【例2.12】用switch语句重写例2.9。
在例2.9中,用if对成绩进行判断:
if(score>=90)
……
score是一个整型数,满足条件“score>=90”的score有11个;如果score是一个浮点数,则score有无数多个——用switch语句时无法全部列举出score的值。所以,需要对score进行等值转换,转换成有限的几个值,甚至一个值,这时就可以用switch语句进行处理了。
表达式:
score/10
可以将成绩转换成有限个整型数。如成绩在90~100之间,可以得到整型数9或10;成绩在80~89之间,可以得到8,……,成绩在0~59之间可以得到整型数0、1、2、3、4或5。
通过上面的处理,可以得到较少的整型数,从而可以用switch语句进行判断。
【代码】
import java.util.Scanner;
public class Example2_12
{
public static void main(String args[])
{
int score,grade;
Scanner reader=new Scanner(System.in);
System.out.print("输入成绩:");
score=reader.next Int();
grade=score/10;
switch(grade)
{
default: //default在最前面
System.out.println("成绩输入错误
case 10:
System.out.println("优秀");
case 9:
System.out.println("优秀");
case 8:
System.out.println("良好");
case 7:
System.out.println("中等");
case 6:
System.out.println("及格");
case 5:
System.out.println("不及格");
case 4:
System.out.println("不及格");
case 3:
System.out.println("不及格");
case 2:
System.out.println("不及格");
case 1:
System.out.println("不及格");
case 0:
System.out.println("不及格");
}
}
}
程序运行结果如图2-14所示。
图2-14 例2.12运行结果
这个程序有两个问题。一个是虽然程序运行正确,但结果不正确,另一个是程序中有较多的重复语句。
break语句
在switch语句的执行过程中,某一种情况(case)下,可能有多组语句被执行,如本例。如果想使某一情况下只执行某一语句组,可以在每一语句组后加上“break”语句。“break”语句可以提前结束switch的执行,后面的语句组都不被执行了。
每一个语句组后面加上“break”后的switch语句的语法形式:
switch(表达式)
{
case 常量1:
语句组1;break;
case 常量2:
语句组2;break;
……
case 常量n:
语句组n;break;
default:
语句组n+1;
}
在运行时,如果“表达式”的值和“常量1”相等,则程序开始执行“语句组1”,执行完成后再执行“break”语句,此时程序会转向“}”下面的语句继续运行,而其他语句组就不被执行了。
加上“break”语句后,switch语句的执行过程如图2-15所示。
图2-15 带break的switch语句的执行过程
另外一个解决问题的方法是,让多个“case”共用一组语句(相当于有的case语句组是一个空的语句组)。
【例2.13】重写例2.12,使程序能有正确的运行结果。
【代码】
import java.util.Scanner;
public class Example2_13
{
public static void main(String args[])
{
int score,grade;
Scanner reader=new Scanner(System.in);
System.out.print("输入成绩:");
score=reader.next Int();
grade=score/10;
switch(grade)
{
case 10:
case 9:
System.out.println("优秀");break;
case 8:
System.out.println("良好");break;
case 7:
System.out.println("中等");break;
case 6:
System.out.println("及格");break;
case 5:
case 4:
case 3:
case 2:
case 1:
case 0:
System.out.println("不及格");break;
default://default放在最后
System.out.println("成绩输入错误!");
}
}
}
程序运行结果如图2-16所示。
图2-16 例2.13运行结果
再从程序结构看,这个程序就简洁多了!
2.3.3 循环控制语句
有些问题,需要采用同一方法进行重复处理。如果用程序来解决这样的问题,就要用到循环结构。
循环结构根据一定的条件可以对问题或问题的部分进行反复处理,直到条件不满足结束循环。含有循环结构的程序可以更有效地利用计算机。
Java语言中有3种循环控制语句,分别是while循环、do-while循环和for循环。
1.while循环
while循环是先判断条件是否为真,如果为真,则执行循环体。
while循环
while循环的语句形式:
“循环条件”可以是一个逻辑常量(true或false)、一个逻辑变量,更多的时候是一个关系或逻辑表达式,用于表示循环是否能进行的条件。“while”之后是循环执行的循环体,循环体可以是一条语句,也可以是多条语句。如果是一条语句作为循环体,使用“形式1”;如果是多条语句作为循环体,则使用“形式2”,加“{}”使得循环体成为一个复合语句。当然,“形式1”的循环体也可以加“{}”,但通常情况下都不加。
while语句的执行过程是,先计算“循环条件”。如果“循环条件”的值为“true”,则执行“循环体”;循环体执行结束后,程序会返回到while处再计算“循环条件”,如果其值仍然为“true”,则再执行“循环体”,……,重复这个过程,直到“循环条件”的值为“false”,“循环体”不再被执行,程序接着执行while语句的下一条语句。
while语句的执行过程如图2-17所示。
图2-17 while的执行过程
while语句与if语句有相似之处,但if语句执行一次之后不能再返回计算“条件表达式”的值,而while语句可以。
编写循环程序时,关键要找出循环条件和重复执行的语句(循环体)。
【例2.14】计算1+2+3+…+100值。
此例可以用归纳法进行计算。前50项中的某一个数与后50项中的位置对称的数,其和为101,而这样的数共有50个,从而可算出和是多少。
现在不用归纳法,而是一个数一个数累加地计算,即表示出求和的过程。设sum表示和值,i表示其中的某一个数。开始时sum=0、i=1,可以写出下面的计算过程:
从上述计算过程可以看到,每一次的计算过程都一样,所以可以把“sum=sum+i;i++”作为一个循环体。
“循环条件”是不能超过100次。因为被累加的数i和循环次数相同,所以可以用i控制循环次数。当i≤100时,让循环重复执行。
【代码】
public class Example2_14
{
public static void main(String args[])
{
int sum,i;
sum=0;//变量初始化
i=1;
while(i<=100)
{
sum=sum+i;
i++;
}
System.out.println("sum="+sum);
}
}
上面程序中的循环语句可以写成:
while(i<=100)//循环体只有一条语句,可以去掉括号
sum=sum+i++;
或
while(i<=100) sum=sum+i++;//写在一行
或
while(i<=100){sum=sum+i;i++;}//写在一行
编写程序时,通常都不写成后两种形式。
下面利用循环语句,再写一个通用的累加程序。
【例2.15】给定一个数列,已知数列的第1个数、数的增量(正数)和最大的数,计算这个数列各元素之和。
设数列的第1个数为a,增量为d,最大数为b,则数列中某一个数为
ai+1=ai+d
当ai+1≤b时,重复执行“sum=sum+ai”。
【代码】
import java.util.Scanner;
public class Example2_15
{
public static void main(String args[])
{
int sum=0;
int a,b,d;
Scanner reader=new Scanner(System.in);
System.out.print("输入数列的初值、增量和终值:");
a=reader.next Int();
d=reader.next Int();
b=reader.next Int();
while(a<=b)
{
sum=sum+a;
a=a+d;
}
System.out.println("sum="+sum);
}
}
程序运行结果如图2-18所示。
图2-18 例2.15运行结果
2.do-while循环
do-while循环
do-while循环是先执行循环体,再根据条件确定是否能再执行循环体。
do-while循环的语句形式:
同样,如果多条语句作为循环体,需要加“{}”使其成为一个复合语句,此时这个复合语句作为循环体。“循环条件”一定要是关系或逻辑表达式,表示循环是否能进行的条件。注意,“while”最后有“;”。
do-while的执行过程是,先执行一遍循环体,然后计算“循环条件”。如果“循环条件”的值为“true”,则再执行循环体;循环体执行结束后,再计算“循环条件”,……,一直重复这个过程,直到“循环条件”的值为“false”,循环结束,接着执行do-while下面的语句。执行过程如图2-19所示。
图2-19 do-while的执行过程
【例2.16】用do-while语句重写例2.14。
【代码】
public class Example2_16
{
public static void main(String args[])
{
int sum=0,i=1;
do
{
sum=sum+i;
i++;
}while(i<=100);
System.out.println("sum="+sum);
}
}
循环体可以写成:
do
sum=sum+i++;//只有一条语句,不用加“{}”
while(i<=100);
或
do sum=sum+i++;while(i<=100);//写成一行
或
do{sum=sum+i;i++;}while(i<=100);
一般不写成后两种形式。
【例2.17】输出斐波那契数列。斐波那契数列的前两项都是1,从第3项开始,每一项都是前两项之和,如:
1,1,2,3,5,8,13……
编写程序找出斐波那契数列前36项元素并输出,每行输出6个元素,每个元素占10位。
【代码】
public class Example2_17
{
public static void main(String args[])
{
long f1=1,f2=1;
int counter=0;
String format="%10d";//输出格式
do
{
System.out.printf(format+format, f1,f2);//format+format=>"%10d%10d"
counter+=2;
if(counter%6==0)//循环中嵌套了if语句
System.out.println();//每行6个,输出换行
f1=f1+f2;//输出前两个数后,f1表示第3个元素,
f2=f2+f1;//f2表示第4个元素,以此类推……
}while(counter<36);//条件不是<=
}
}
程序运行结果如图2-20所示。
图2-20 例2.17运行结果
do-while循环与while循环的关键字有相同之处,在语法上也类似,但执行过程有区别。
对于do-while循环,循环体至少被执行一次,因为执行一次后才会计算循环条件;而对于while循环,循环体可能一次也不被执行,因为当第一次计算循环条件时就可能为“false”。
多数情况下,while和do-while可以互相替代。
3.for循环
for循环
for循环是3种循环中最灵活、使用最多的循环。在for循环中,可以对变量(循环控制变量)进行初始化、控制循环(循环条件)和使变量变化(循环控制变量增量)。
for循环的一般语法形式:
for(变量初始化表达式;循环条件表达式;变量增量表达式)
循环体
“变量初始化表达式”用于对变量尤其是循环控制变量进行初始化,“循环条件表达式”用于确定是否能进行循环,“变量增量表达式”用于对变量尤其是循环控制变量赋新值。
for循环的执行过程是:
变量初始化表达式→循环条件表达式(=true)→循环体→变量增量表达式→
循环条件表达式(=true)→循环体→变量增量表达式→
……
循环条件表达式(=false)→循环结束
在for循环中,“变量初始化表达式”只在循环开始时计算一次,“变量增量表达式”从循环第2次开始时每次都被计算一次,“循环条件表达式”在每次循环时都要被计算一次。
可以用图2-21表示for循环的执行过程。
图2-21 for语句的执行过程
【例2.18】用for语句重写例2.14。
public class Example2_18
{
public static void main(String args[])
{
int sum,i;
//sum和i都在变量初始化表达式中被初始化
for(sum=0,i=1;i<=100;i++)
sum=sum+i;
System.out.println("sum="+sum);
}
}
循环语句也可以写成:
for(sum=0,i=1;i<=100;i++)sum=sum+i;
但是通常都是分行写。
【例2.19】判断一个自然数是否是素数。所谓素数是指,如果一个数只能被1和自身整除,则该数是素数,又称为质数。
按照素数的定义,对于一个自然数x,如果在2 ~(x-1)范围内没有x的因子,则x是一个素数。
【代码】
import java.util.Scanner;
public class Example2_19
{
public static void main(String args[])
{
int x,i;
boolean prime=true;//先假设x是素数
Scanner input=new Scanner(System.in);
System.out.print("输入一个自然数:");
x=input.next Int();
//通过循环判断是否有因子
for(i=2;i<=x-1;i++)//i在2~(x-1)之间
if(x%i==0)//i是x的因子
prime=false;
System.out.print(x);
if(prime)
System.out.println("是素数。");
else
System.out.println("不是素数。");
}
}
程序运行结果如图2-22所示。
图2-22 例2.19运行结果
一个数的因子除该数本身外不可能大于该数的一半,所以上述循环语句可以写成:
for(i=2;i<=x/2;i++) //i在2~x/2之间
if(x%i==0) //i是x的因子
prime=false;
计算量减少了一半,从而提高程序的执行效率。去掉注释后可以写成一行:
for(i=2;i<=x-1;i++)if(x%i==0)prime=false;
但是通常不能这样写。
更快的方法是在2~之间找x的因子。因为从2开始,只要找到一个因子,x就不是素数,就没必要再往后找其他的因子了,循环就应结束,所以循环语句写成:
for(i=2;i<=(int)Math.sqrt(x) && prime;i++)
if(x%i==0) //i是x的因子
prime=false;
注意循环条件的写法,这样的写法又可以减少计算量。
for语句是可以灵活使用的循环。for语句中有3个表达式,根据需要,3个表达式中可以没有任何一个、没有任何两个,甚至3个表达式都可以没有。
for语句的6种形式
如果没有第1个表达式,则应该将变量初始化的语句放在for语句之前;如果没有第2个表达式,表示循环条件永远为“true”,这时需要在循环体中用if语句进行判断,以便在适当的时机结束循环;如果没有第3个表达式,则应该将变量的增量放在循环体的后面部分。
以例2.18为例,其中的for语句可以写出下面几种形式。
形式1:没有第1个表达式,变量i的初始化在for之前用赋值语句实现。
sum=0;
i=1;
for(;i<=100;i++)
sum+=i;
形式2:没有第2个表达式,循环结束的条件在循环体中判断,其中的break语句用于结束循环。
sum=0;
for(i=1;;i++)
{
sum+=i;
if(i>=100)
break;
}
形式3:没有第3个表达式,变量i的改变放在循环体中,成为循环体中的一条语句。
sum=0;
for(i=1;i<=100;)
{
sum+=i;
i=i+1;
}
形式4:没有第1个表达式和第3个表达式,综合使用形式1和形式3。
sum=0;
i=1;
for(;i<=100;)
{
sum+=i;
i++;
}
形式5:3个表达式都没有,综合使用形式1、形式2和形式3。
sum=0;
i=1;
for(;;)
{
sum+=i;
if(i>=100)
break;
i++;
}
形式6:循环体是空循环体,累加过程放在第3个表达式中。
for(sum=0,i=1;i<=100;sum+=i,i++)
;
虽然是空循环体,但“;”不能少。
4.for循环的嵌套
for循环的嵌套
如果循环体中还有循环语句,则形成循环的嵌套。以下是几种循环的嵌套形式。
在执行时,可以将被嵌套的语句看作一条语句。当这条语句执行结束后,才能进行外层循环的下一次循环。
【例2.20】给定两个自然数,找出这两个自然数之间的所有素数。
在例2.19中可知,判断一个数x是否是素数,可以通过下面的语句实现:
for(i=2;i<=(int)Math.sqrt(x) && prime;i++)
if(x%i==0) //i是x的因子
prime=false;
现在要找出两个数之间的所有素数,虽然数值不同,但是判断过程都一样,所以只需让每一个数重复一遍上述过程即可。
【代码】
import java.util.Scanner;
public class Example2_20
{
public static void main(String args[])
{
int a,b,x,i;
int counter=0;//素数个数计数器
boolean prime=true;
Scanner input=new Scanner(System.in);
System.out.print("输入两个自然数:");
a=input.next Int();
b=input.next Int();
if(a>b)//交换两个数的值,使得a小、b大
{
x=a;//交换两个数需要通过第3个数实现
a=b;
b=x;
}
x=a%2==0?a+1:a;//x从奇数开始,偶数不能是素数
while(x<=b)//用while循环
{
prime=true;//先假设x是素数
//通过循环再进一步确认,循环嵌套
for(i=2;i<=(int)Math.sqrt(x)&′i++)
if(x%i==0)
prime=false;
if(prime)
{
System.out.printf("%5d", x);
counter++;
if(counter%10==0) //每行输出10个素数
System.out.println();
}
x+=2;//只判断素数
}
if(counter%10!=0)//最后一行不足10个素数时也要换行
System.out.println();
System.out.printf("总共%d个素数。", counter);
}
}
程序运行结果如图2-23所示。
图2-23 例2.20运行结果
【例2.21】给定数1、2、3和4,由这4个数字能组成多少个数字不重复的三位数?
设i、j和k是一个三位数的百、十和个位数,这3个数互不相同(不重复)的条件是:
i!=j && i!=k && j!=k
采用穷举法,将1、2、3和4能组成的每一个三位数都判断一下。如果满足上述条件,则可以得到不重复的三位数。用嵌套的循环实现。
【代码】
public class Example2_21
{
public static void main(String args[])
{
int i,j,k;
int counter=0;
for(i=1;i<=4;i++)//三重循环
for(j=1;j<=4;j++)
{
if(i!=j)//前两位不相同再往下计算,可以减少计算量
for(k=1;k<=4;k++)
if(i!=k && j!=k)//满足条件,则互不相同
{
System.out.printf("%4d",i*100+j*10+k);
counter++;
if(counter%5==0)
System.out.println();
}
}
if(counter%5!=0)//最后一行不足5个素数也要换行
System.out.println();
System.out.printf("总共%d个不重复的三位数。",counter);
}
}
程序运行结果如图2-24所示。
图2-24 例2.21运行结果
Java对循环嵌套的层数没有限制,但最多不要超过三层。
2.3.4 选择控制语句与循环控制语句的嵌套
在2.3.3小节中分别讲述了选择控制语句和循环控制语句。
在实际使用时,两种控制语句经常被混用,选择语句嵌套循环语句,或者循环语句嵌套选择语句。但多数情况下,都是循环控制语句嵌套选择控制语句,如例2.20和例2.21中就是在循环控制语句中嵌套了选择控制语句。
2.3.5 break语句与continue语句
break语句和continue语句都是控制转移语句。
对于循环控制语句,只有当循环条件为假时,循环才会结束。如果循环条件为真并且想使循环提前结束,可以使用break语句和continue语句。
break语句和continue语句用在循环中,可以使循环提前结束。但break语句和continue语句有区别。
break语句和continue语句一般不能单独用在循环中,基本上都是与选择语句配合使用,也就是作为选择语句的子句。
1.break语句
在前面介绍switch语句时讲过break语句。break语句用于switch语句中可以提前结束switch语句。
break语句
break语句更多是被用在循环语句中。break语句用在循环中可以提前结束它所在的循环语句,不管后面还有多少次循环都不再被执行了。
break语句可以分成基本的break语句和带标号的break语句。
(1)基本的break语句
基本的break语句的语法形式:
break;
一定要将这个语句放到循环体中,否则会出现编译错误。
在例2.20中,判断一个数是否是素数的过程:
for(i=2;i<=(int)Math.sqrt(x)&′i++)
if(x%i==0)
prime=false;
也可以写成:
for(i=2;i<=(int)Math.sqrt(x);i++)//注意循环条件
if(x%i==0)
{
prime=false;
break;//如果i是因子,则没必要再判断,用break结束循环
}
当一个数在指定范围内有一个因子,该数就不是素数,没有必要往下再找是否还有因子了,所以用break语句结束循环。
【例2.22】计算1!+2!+3!+…,直到某一个数的阶乘大于10 000 000为止(大于1000_0000的数不累加)。
这是一个有规律的累加问题,所以可以用循环来解决。但是,循环多少次,或者什么情况下执行循环(循环条件),程序未运行时不可知。
所以,在程序运行时,对每一个阶乘数先判断是否大于10 000 000,如果大于则结束循环,结束循环时就可以用break语句。
另外,对于每一个数的阶乘,不必每次都从1开始算起,只需在前一个阶乘的基础上再乘下一个数即可。
【代码】
public class Example2_22
{
public static void main(String[] args)
{
long sum=0;//表示和值,可能比较大
int item=1,i=1;//item表示每一个阶乘
while(true)//无限(死)循环
{
if(item>1000_0000)
{
System.out.print("=");//结束时
break;
}
else if(i>1)
System.out.print("+");//未结束
sum=sum+item;//将一个阶乘累加到sum中
System.out.print(i+"!");//输出i!
i++;//下一个数
item=item*i;//下一个数的阶乘
}
System.out.printf("%,d\n",sum);
}
}
程序运行结果如图2-25所示。
图2-25 例2.22运行结果
(2)带标号的break语句
基本的break语句使它所在的循环提前结束,而带标号的break语句可以使标号所指的循环提前结束。
带标号的break语句的语法形式:
标号:
……
break 标号;
其中“标号”是合法的标识符,指向循环时后面加一个“:”。
一般地,带标号的break语句多用在多重循环中,用于在内层循环中提前结束外层的循环。
【例2.23】找出从100开始的若干个素数,直到某一个非素数的第一个因子大于15为止。
【代码】
public class Example2_23
{
public static void main(String args[])
{
int x,x1,i;
int counter=0;/*素数计数器*/
boolean prime=true;
label://标号
for(x=101;;x+=2)//无限循环
{
prime=true;
x1=(int)Math.sqrt(x);
for(i=2;i<=x1;i++)
if(x%i==0)
{
if(i>15)//非素数第1个因子大于15
break label;//结束外层循环
//break label所在的循环是内层循环,
//但结束的是外层循环
prime=false;
break;//注意:break所在的循环是内层循环
}//当break被执行的时候,结束的是内层循环,
//而不是外层循环
if(prime)
{
System.out.printf("%4d",x);
counter++;
if(counter%5==0)/*输出的每一行素数是5的倍数则换行*/
System.out.println();
}
}
}
}
程序运行结果如图2-26所示。
图2-26 例2.23运行结果
2.continue语句
continue语句
continue语句用在循环中,可以使它所在循环的当前一次循环提前结束,即使它下面还有语句也不再执行,接着执行下一次循环。
continue语句也分为基本的continue语句和带标号的continue语句。
continue语句只结束当前一次循环,后面的循环还能继续执行;而break语句则使它所在的循环完全结束,无论后面还有多少次循环都不再执行。
(1)基本的continue语句
基本的continue语句的语法形式:
continue;
这条语句必须在一个循环体中。
在例2.21中,三重循环也可以写成下面的形式:
for(i=1;i<=4;i++)//三重循环
for(j=1;j<=4;j++)
{//循环体内共有两条语句:if和for
//if(i!=j)改成i==j
if(i==j)//语句1
continue;//当i==j时,可以使第2层循环提前结束,
//下面的for语句不能被执行
for(k=1;k<=4;k++)//语句2
if(i!=k && j!=k)//满足条件,则互不相同
{
System.out.printf("%4d",i*100+j*10+k);
counter++;
if(counter%5==0)
System.out.println();
}
}
【例2.24】从键盘输入若干个正整数,将其中不能被3整除的数累加在一起,并输出其和,当输入负数时结束。
【代码】
import java.util.Scanner;
public class Example2_24
{
public static void main(String args[])
{
int sum=0,x;
Scanner reader=new Scanner(System.in);
System.out.println("输入若干个正整数,以负数结束:");
while((x=reader.next Int())>0)
{
if(x%3==0)
continue;//与continue在同一循环体内还有下面一条语句
//当执行到continue语句后,当前循环的下面语句不被执行,
//继续下一次循环
sum=sum+x;
}
System.out.println("sum="+sum);
}
}
程序运行结果如图2-27所示。
图2-27 例2.24运行结果
本例只为说明如何使用continue语句。采用下面的形式,程序更合理:
while((x=reader.next Int())>0)
if(x%3!=0)//注意条件
sum=sum+x;
(2)带标号的continue语句
带标号的continue语句使它标号所指的当前一次循环提前结束,后面的若干次循环还能继续执行。它的语法形式:
标号:
……
continue标号;
带标号的continue语句一般用在多重循环中,“标号”指向外层循环。
【例2.25】带标号的continue语句的使用。
【代码】
public class Example2_25
{
public static void main(String args[])
{
int i,j;
label://标号
for(i=1;i<=3;i++)
{
for(j=1;i<=50;j++)
{
if(i+j>4)
continue label;//转向外层循环
System.out.println("i:"+i+",j:"+j);
}
}
}
}
程序运行结果如图2-28所示。
图2-28
例2.25运行结果
在例2.25中,按照i和j值,应该循环150次,但是由于内层循环有带标号的continue语句,在没有达到循环次数的时候就提前结束了,所以一共只循环了6次。外层循环正常结束。