控制语句
0.前定义
语句块(有时叫做复合语句),是用花括号扩起的任意数量的简单Java语句。
块确定了局部变量的作用域。块中的程序代码,作为一个整体,是要被一起执行的。
块可以被嵌套在另一个块中,但是不能在两个嵌套的块内声明同名的变量。
语句块可以使用外部的变量,而外部不能使用语句块中定义的变量,因为语句块中定义的变量作用域只限于语句块。
1 public class Test { 2 public static void main(String[] args) { 3 int n; 4 int a; 5 { 6 int k; 7 int n; //编译错误:不能重复定义变量n 8 } //变量k的作用域到此为止 9 } 10 }
Java里的语句可分为以下六类
- 方法调用语句:如:System.out.println(" Hello");
- 表达式语句:表示式尾加上分号。比如赋值语句:x=23;
- 复合语句:可以用{ }把一些语句括起来构成复合语句, 如:{ z=123+x; System.out.println("How are you"); }
- 空语句:一个分号也是一条语句,称做空语句。
- 控制语句:控制语句分为条件分支语句、开关语句和循环语句。
- package语句和 import语句:它们和类、对象有关,package是java放在哪,import指定导入包
1.综述
流程控制语句是用来控制程序中各语句执行顺序的语句,可以把语句组合成能完成一定功能的小逻辑模块。
控制语句分为三类:顺序、选择和循环。
顺序结构:代表“先执行a,再执行b”的逻辑。
选择结构:代表“如果…,则…”的逻辑,
循环结构:代表“如果…,则再继续…”的逻辑。
递归结构:自己调用自己
迭代结构:不停调用另一个
2.介绍
2.1 选择结构
选择结构用于判断给定的条件,然后根据判断的结果来控制程序的流程。
有如下结构:
if单选择结构
if-else双选择结构
if-else if-else多选择结构
switch结构
2.1.1 if单选择结构
if语句是单条件分支语句,即根据一个条件来控制程序执行的流程
if(布尔表达式){ 语句块 }
if语句对布尔表达式进行一次判定,
若判定为真,则执行{}中的语句块,否则跳过该语句块
if(count >= 10 && count <= 15) { //错误写法:10<=count<=15 System.out.println("1"); }
注意:如果if语句不写{},则只能作用于后面的第一条语句。
表达式的值必须是boolean型的;不能用0代表false;用1代表true;
//例子2将变量a,b,c内存中的数值按大小顺序进行互换(从小到大排列)。 public class Example3_2 { public static void main(String args[]) { int a = 9,b = 5,c = 7,t=0; if(b<a) { t = a; a = b; b = t; } if(c<a) { t = a; a = c;c = t; } if(c<b) { t = b; b = c; c = t; } System.out.println("a="+a+",b="+b+",c="+c); } }
2.1.2 if-else双选择结构
if-else 语句是双条件分支语句,即根据一个条件来控制程序执行的流程
if(布尔表达式){ 语句块1 }else{ 语句块2 }
当布尔表达式为真时,执行语句块1,否则,执行语句块2。也就是else部分。
if (a<b) { System.out.println(a); } else { System.out.println(b); }
注意:条件运算符有时候可用于代替if-else
System.out.println((a<b)?a:b);
2.1.3 if-else if-else多选择结构
if-else-if 语句是多条件分支语句,即根据多个条件来控制程序执行的流程
if(布尔表达式1) { 语句块1; } else if(布尔表达式2) { 语句块2; }……else if(布尔表达式n){ 语句块n; } else { 语句块n+1; }
当布尔表达式1为真时,执行语句块1;否则,判断布尔表达式2,当布尔表达式2为真时,执行语句块2;否则,继续判断布尔表达式3······;如果1~n个布尔表达式均判定为假时,则执行语句块n+1,也就是else部分。
1 if (age < 15) { 2 System.out.println("儿童"); 3 } else if (age < 25) { 4 System.out.println("青年"); 5 } else if (age < 45) { 6 System.out.println("中年"); 7 } else if (age < 65) { 8 System.out.println("中老年"); 9 } else if (age < 85) { 10 System.out.println("老年"); 11 } else { 12 System.out.println("老年"); 13 }
2.1.4 switch多选择结构
switch 语句是单条件多分支的开关语句
它的一般格式定义如下(其中break语句是可选的):
switch(表达式) { case 常量值1: 若干个语句 break; case 常量值2: 若干个语句 break; ... case 常量值n: 若干个语句 break; default: 若干语句 }
说明:
1)表达式的值必须是:byte,short, Int,char不能是String或者long型的; (与int兼容类型)
2)default语句放的位置是任意的。
3)检查时case 常量必须与switch表达式 可用的类型相同。
4)switch语句会根据表达式的值从相匹配的case标签处开始执行,
一直执行到break语句处或者是switch语句的末尾。
如果表达式的值与任一case值不匹配,则进入default语句(如果存在default语句的情况)。
1 public class Test{ 2 public static void main(String[] args) { 3 char c = 'a'; 4 int rand = (int) (26 * Math.random()); 5 char c2 = (char) (c + rand); 6 System.out.print(c2 + ": "); 7 switch (c2) { 8 case 'a': 9 case 'e': 10 case 'i': 11 case 'o': 12 case 'u': 13 System.out.println("元音"); 14 break; 15 case 'y': 16 case 'w': 17 System.out.println("半元音"); 18 break; 19 default: 20 System.out.println("辅音"); 21 } 22 } 23 }
注意:
1)根据表达式值的不同可以执行许多不同的操作。
switch语句中case标签在JDK1.5之前必须是整数(long类型除外)或者枚举,不能是字符串,
在JDK1.7之后允许使用字符串(String)。
2)当布尔表达式是等值判断的情况,可以使用if-else if-else多选择结构或者switch结构,
如果布尔表达式区间判断的情况,则只能使用if-else if-else多选择结构。
//例子4使用了switch语句判断用户从键盘输入的正整数是否为中奖号码。 import java.util.Scanner; public class Example3_4{ public static void main(String args[]) { int number = 0; System.out.println("输入正整数(回车确定)"); Scanner reader = new Scanner(System.in); number = reader.nextInt(); switch(number) { case 9 : case 131 : case 12 : System.out.println(number+"是三等奖"); break; case 209 : case 596 : case 27 : System.out.println(number+"是二等奖"); break; case 875 : case 316 : case 59 : System.out.println(number+"是一等奖"); break; default: System.out.println(number+"未中奖"); } } }
2.2 循环结构
循环结构分两大类,一类是当型,一类是直到型。
当型: 当布尔表达式条件为true时,反复执行某语句,当布尔表达式的值为false时才停止循环,比如:while与for循环。
直到型: 先执行某语句, 再判断布尔表达式,如果为true,再执行某语句,如此反复,直到布尔表达式条件为false时才停止循环,比如do-while循环。
2.2.1 while循环
while (布尔表达式) { 循环体; }
在循环刚开始时,会计算一次“布尔表达式”的值,若条件为真,执行循环体。而对于后来每一次额外的循环,都会在开始前重新计算一次。
int i = 0; int sum = 0; // 1+2+3+…+100=? while (i <= 100) { sum += i;//相当于sum = sum+i; i++; }
注意:语句中应有使循环趋向于结束的语句,否则会出现无限循环–––"死"循环。
2.2.2 do-while循环
do { 循环体; } while(布尔表达式) ;
do-while循环结构会先执行循环体,然后再判断布尔表达式的值,若条件为真,执行循环体,当条件为假时结束循环。
int i = 0; int sum = 0; do { sum += i; // sum = sum + i i++; } while (i <= 100);//此处的;不能省略 System.out.println("Sum= " + sum);
注意:while与do-while的区别
do-while循环的循环体至少执行一次
public class Test{ public static void main(String[] args) { //while循环:先判断再执行 int a = 0; while (a < 0) { System.out.println(a); a++; } System.out.println("-----"); //do-while循环:先执行再判断 a = 0; do { System.out.println(a); a++; } while (a < 0); }
2.2.3 for循环
for (初始表达式; 布尔表达式; 迭代因子) { 循环体; }
for循环语句是支持迭代的一种通用结构,是最有效、最灵活的循环结构。
for循环在第一次反复之前要进行初始化,即执行初始表达式;
随后,对布尔表达式进行判定,若判定结果为true,则执行循环体,
否则,终止循环;
最后在每一次反复的时候,进行某种形式的“步进”,即执行迭代因子。
A. 初始化部分设置循环变量的初值
B. 条件判断部分为任意布尔表达式
C. 迭代因子控制循环变量的增减
for循环在执行条件判定后,先执行的循环体部分,再执行步进。
//求1-100之间的累加和 for (int i = 0; i <= 100; i++) { sum += i; } System.out.println("Sum= " + sum);
注意:
1)在控制表达式的初始化和步进控制部分,可以使用一系列由逗号分隔的表达式,而且那些表达式均会独立执行。
1. 无论在初始化还是在步进部分,语句都是顺序执行的。
2. 尽管初始化部分可设置任意数量的定义,但都属于同一类型。
3. 约定:只在for语句的控制表达式中写入与循环变量初始化,条件判断和迭代因子相关的表达式。
4.初始化部分、条件判断部分和迭代因子可以为空语句,但必须以“;”分开
1 public class Test { 2 public static void main(String[] args) { 3 for(int i = 1, j = i + 10; i < 5; i++, j = i * 2) { 4 System.out.println("i= " + i + " j= " + j); 5 } 6 } 7 }
2)无限循环
for ( ; ; ) { // 无限循环: 相当于 while(true) System.out.println("北京尚学堂");) }
3)初始化变量的作用域
for ( int i=1; i<10; i++) { System.out.println("1"); } System.out.println(i+“、”) //编译错误,无法访问在for循环中定义的变量i
2.2.4 嵌套循环
在一个循环语句内部再嵌套一个或多个循环,称为嵌套循环。
while、do-while与for循环可以任意嵌套多层。
for (int i=1; i <=5; i++) { for(int j=1; j<=5; j++){ System.out.print(i+" "); } System.out.println(); }
2.2.5 break语句和continue语句
1)在任何循环语句的主体部分,均可用break控制循环的流程。
break用于强行退出循环,不执行循环中剩余的语句。
1 public class Test { 2 public static void main(String[] args) { 3 int total = 0;//定义计数器 4 System.out.println("Begin"); 5 while (true) { 6 total++;//每循环一次计数器加1 7 int i = (int) Math.round(100 * Math.random()); 8 //当i等于88时,退出循环 9 if (i == 88) { 10 break; 11 } 12 } 13 //输出循环的次数 14 System.out.println("Game over, used " + total + " times."); 15 } 16 }
2)continue 语句用在循环语句体中,用于终止某次循环过程,
即跳过循环体中尚未执行的语句,
接着进行下一次是否执行循环的判定。
注意事项
1. continue用在while,do-while中,continue 语句立刻跳到循环首部,越过了当前循环的其余部分。
2. continue用在for循环中,跳到for循环的迭代因子部分。
1 public class Test{ 2 public static void main(String[] args) { 3 int count = 0;//定义计数器 4 for (int i = 100; i < 150; i++) { 5 //如果是3的倍数,则跳过本次循环,继续进行下一次循环 6 if (i % 3 == 0){ 7 continue; 8 } 9 //否则(不是3的倍数),输出该数 10 System.out.print(i + "、"); 11 count++;//没输出一个数,计数器加1 12 //根据计数器判断每行是否已经输出了5个数 13 if (count % 5 == 0) { 14 System.out.println(); 15 } 16 } 17 } 18 }
3)“标签”是指后面跟一个冒号的标识符,例如:“label:”。
对Java来说唯一用到标签的地方是在循环语句之前。
而在循环之前设置标签的理由是:在其中嵌套另一个循环,
由于break和continue关键字通常只中断当前循环,
但若随同标签使用,它们就会中断到存在标签的地方。
1 public class Test { 2 public static void main(String args[]) { 3 outer: for (int i = 101; i < 150; i++) { 4 for (int j = 2; j < i / 2; j++) { 5 if (i % j == 0){ 6 continue outer; 7 } 8 } 9 System.out.print(i + " "); 10 } 11 } 12 }
4)goto关键字很早就在程序设计语言中出现。尽管goto仍是Java的一个保留字,但并未在Java语言中得到正式使用;Java没有goto语句。然而,在break和continue这两个关键字的身上,仍然能看出一些goto的影子---带标签的break和continue。
在 “goto有害”论中,最有问题的就是标签,而非goto, 随着标签在一个程序里数量的增多,产生错误的机会也越来越多。 但Java标签不会造成这方面的问题,因为它们的活动场所已被限死,不可通过特别的方式到处传递程序的控制权。
2.3 递归结构
1)递归是一种常见的解决问题的方法,即把问题逐渐简单化。
递归的基本思想就是“自己调用自己”,一个使用递归技术的方法将会直接或者间接的调用自己。
利用递归可以用简单的程序来解决一些复杂的问题。比如:斐波那契数列的计算、汉诺塔、快排等问题。
2)递归结构包括两个部分:
1.定义递归头。解答:什么时候不调用自身方法。如果没有头,将陷入死循环,也就是递归的结束条件。
2.递归体。解答:什么时候需要调用自身方法。
1 public class Test { 2 public static void main(String[] args) { 3 long d1 = System.currentTimeMillis(); 4 System.out.printf("%d阶乘的结果:%s%n", 10, factorial(10)); 5 long d2 = System.currentTimeMillis(); 6 System.out.printf("递归费时:%s%n", d2-d1); //耗时:32ms 7 } 8 /** 求阶乘的方法*/ 9 static long factorial(int n){ 10 if(n==1){//递归头 11 return 1; 12 }else{//递归体 13 return n*factorial(n-1);//n! = n * (n-1)! 14 } 15 } 16 }
使用循环求n! public class Test23 { public static void main(String[] args) { long d3 = System.currentTimeMillis(); int a = 10; int result = 1; while (a > 1) { result *= a * (a - 1); a -= 2; } long d4 = System.currentTimeMillis(); System.out.println(result); System.out.printf("普通循环费时:%s%n", d4 - d3); } }
3)递归的缺陷
简单的程序是递归的优点之一。
但是递归调用会占用大量的系统堆栈,内存耗用多,
在递归调用层次多时速度要比循环慢的多,所以在使用递归时要慎重
4)注意事项
任何能用递归解决的问题也能使用迭代解决。
当递归方法可以更加自然地反映问题,并且易于理解和调试,并且不强调效率问题时,可以采用递归;
在要求高性能的情况下尽量避免使用递归,递归调用既花时间又耗内存。
参考:
https://www.cnblogs.com/zhizhan/p/4892886.html