第3章 流程控制

第3章 流程控制

在大量代码实践的基础上,可以发现所有的程序都可以抽象为三类程序结构:顺序结构、分支结构、循环结构。

顺序结构是指,通常情况下,我们编写的代码都是自上而下,依次执行,不会出现跳行执行、逆向执行等情况。

其中分支结构用于实现根据条件来选择性执行某一段代码,因此分支结构也被叫做选择结构。

循环结构则是用于实现根据循环条件重复执行某段代码。

Java提供了if和switch两种分支语句,还有while,do while和for三种循环语句。除此以外,JDK5还提供了增强for循环,foreach循环。以更简洁的书写方式遍历集合、数组。

3.1 顺序结构

任何编程语言中最常见的程序结构就是顺序结构。顺序结构就是程序从上而下逐行执行,中间没有任何的判断和跳转。

如果main方法的多行代码之间没有任何流程控制,则程序总是从上而下依次执行,排在前面的代码先执行,排在后面的代码后执行。

3.2 分支结构

Java提供了两种常见的分支结构:if语句和switch语句,其中if语句使用布尔表达式或者布尔值作为分支结构条件来进行分支控制。

3.2.1 if条件语句

if 语句使用布尔表达式或者布尔值作为分支条件来进行分支控制,if语句有以下三种形式。

  • 单分支结构
if(logic expression){
    statement   
}

单分支情况一般用于判断是否满足某个条件,如果括号内表达式返回值为true,则执行后面大括号中的语句。

示例:

package cn.bytecollege;
/**
 * 本例将演示单分支结构
 * @author MR.W
 *
 */
public class SingleIfDemo {
	public static void main(String[] args) {
		int age = 18;
		if(age>17) {
			System.out.println("您已年满18岁");
		}
	}
}

在上例代码中,我们定义了整型变量age,并赋值为18。在if分支中我们判断age是否大于18,如果大于18则执行大括号中的内容。根据代码可以看出age是大于17的,因此会执行大括号中的语句。

  • 双分支结构

单分支具有一定的局限性,因为单分支结构只能判断一种情况,如果两个条件互斥,则不能很简洁的进行判断。因此有了双分支结构,我们经常会遇到这种情况:我们在注册账号时,需要填写性别,我们知道表示性别的两种情况往往是互斥的,即非此即彼的关系。不是男性,便是女性。当我们用1和2代替性别时,我们可以做以下判断,首先我们使用单分支进行判断。

首先,我们先了解一下双分支结构的语法:

if(logic expression){
    statement   
}else{
    statement   
}

示例:

package cn.bytecollege;
/**
 * 本例将演示使用单分支判断两种情况
 */
import java.util.Scanner;
public class SingleIfDemo2 {
	public static void main(String[] args) {
		System.out.println("---请选择性别---");
		System.out.println("1.男性");
		System.out.println("2.女性");
		Scanner scanner = new Scanner(System.in);
		int gender = scanner.nextInt();
		if(gender == 1) {
			System.out.println("您选择了男性");
		}
		if(gender==2) {
			System.out.println("您选择了女性");
		}
	}
}

在上例中,我们使用了Scanner类的对象,该类是用于等待键盘输入,此处不做过多介绍。

接下来,我们使用双分支来重构上述代码。

package cn.bytecollege;

import java.util.Scanner;

public class DoubleIfDemo {
	public static void main(String[] args) {
		System.out.println("---请选择性别---");
		System.out.println("1.男性");
		System.out.println("2.女性");
		Scanner scanner = new Scanner(System.in);
		int gender = scanner.nextInt();
		if(gender == 1) {
			System.out.println("您选择了男性");
		}else {
			System.out.println("您选择了女性");
		}
	}
}

从示例中我们可以看到,使用双分支结构代码更简洁,阅读方便,书写简便。如果使用单分支结构去判断,那么每种情况都需要判断,这无疑增加了代码的运行时间,降低了效率。但是当使用双分支结构时,因为两个条件互斥,所以只要一个条件不满足,那么一定是另外一种情况。这样提升了代码运行效率。

  • 多分支结构,多分支结构一般用于判断多种情况,条件间也是互斥的,例如,评定学生成绩等级,90分以上评定为A,70到90分评定为B,60-70分评定为C,60分以下评定为D,由于判断情况比较多,很明显单分支效率低,双分支只能判断两种情况,都不能满足需要,此时,就需要用到多分支了。首先咱们了解一下多分支结构的语法
if(logic expression){
    statement   
}else if(logic expression){
    statement   
}
//else if 可以有多个
//else 是指上述情况都不满足时,即进入else,else可以省略
else{
    
}

接下来,我们通过示例来完成上述案例。

package cn.bytecollege;

import java.util.Scanner;

/**
 * 本例将演示多分支结构
 * @author MR.W
 *
 */
public class MutiIfDemo {
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		double score = scanner.nextDouble();
		if(score>=90) {
			System.out.println("A");
		}else if(score>=70&&score<90) {
			System.out.println("B");
		}else if(score>=60&&score<70) {
			System.out.println("C");
		}else if(score>=0&&score<60) {
			System.out.println("D");
		}
	}
}

上例中,通过else if判断了多种情况,但是上述代码还是有一些缺陷,要知道用户并不会完全按照开发者的意愿来使用软件,假如用户此时输入了200,那么程序就会没有任何响应便结束了,这样的用户体验是非常糟糕的,那么如何才能尽可能的让这个程序健壮一些呢,我们只需要在最后一个else if后添加else即可,也就是说添加else以后,当else之前所有的判断条件都不满足的时候,就会进入else中去。那么我们现在重构上述代码。

package cn.bytecollege;

import java.util.Scanner;

/**
 * 本例将演示多分支结构
 * @author MR.W
 *
 */
public class MutiIfDemo {
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		double score = scanner.nextDouble();
		if(score>=90) {
			System.out.println("A");
		}else if(score>=70&&score<90) {
			System.out.println("B");
		}else if(score>=60&&score<70) {
			System.out.println("C");
		}else if(score>=0&&score<60) {
			System.out.println("D");
		}else {
			System.out.println("您的输入有误,请重试!");
		}
	}
}

3.2.2 switch条件语句

switch 语句有一个控制表达式和多个case标签组成,和if语句不同的是,switch语句后面的控制表达式的数据类型只能是byte、short、char、int四种类型,从Java 7以后添加了枚举类型和String类型。

switch语句通常需要在case标签后紧跟一个代码块,case标签作为这个代码块的标识,switch语句的语法格式如下:

switch (expression){    case condition1:        {        	statement(s)                break;        }     case condition2:        {        	statement(s)                break;        }        case condition2:        {        	statement(s)                break;        }     ....      case condition N:        {        	statement(s)                break;        }    default:{        statement (s)    }	}

switch分支语句的执行是先对expression求值,然后依次匹配condition1、condition2 …condition N等值,遇到匹配的值即执行对应的执行体;如果所有的case标签后的值都不与expression表达式的值相等,则执行default标签后的代码块。

和if语句不同的是,switch语句中各case标签后代码块的开始点和结束点非常清晰,因此完全可以省略case后代码块的花括号。与if语句中的else类似,switch语句中的default看似没有条件,其实是有条件的,条件就是expression表达式的值不能与前面任何一个case标签后的值相等。

package cn.bytecollege;/** * 本例将演示switch语句 * @author MR.W * */public class SwitchDemo {	public static void main(String[] args) {		//声明变量score,并赋值为'C'		char score = 'C';		switch (score) {		case 'A':			System.out.println('A');			break;		case 'B':			System.out.println('B');			break;		case 'C':			System.out.println('C');			break;		case 'D':			System.out.println('D');			break;		default:			System.out.println("输入有误,请重试");		}	}}

运行上面的程序可以看出输出了“不及格”,而变量score的值对应的就是不及格,结果没有任何问题。需要注意的是在每个case中代码末尾都有break,break在这里指中断的意思,也就是当条件匹配以后,switch语句即可中断,再不进行以后的判断。那么如果省略了break,程序又会发生什么呢?

package cn.bytecollege;/** * 本例将演示switch语句 * @author MR.W * */public class SwitchDemo {	public static void main(String[] args) {		//声明变量score,并赋值为'C'		char score = 'C';		switch (score) {		case 'A':			System.out.println("优秀");		case 'B':			System.out.println("良好");		case 'C':			System.out.println("及格");		case 'D':			System.out.println("不及格");		default:			System.out.println("输入有误,请重试");		}	}}

运行以上程序:

img

这个结果有些怪异,但是这正是有switch语句的运行流程决定的:switch语句会先求出expression表达式的值,然后用这个表达式的值和case标签后的值进行比较,一旦遇到相等的值,程序就执行case标签后的代码,不在判断与后面case、default标签的条件是否匹配,除非遇到break才会结束。

Java 7增强了switch语句的功能,switch后的表达式支持String(字符串)类型的变量或表达式。下面我们通过示例来学习。

package cn.bytecollege;public class SwitchDemo2 {	public static void main(String[] args) {				String week = "周三";		switch (week) {		case "周一":			System.out.println("今天是周一");			break;		case "周二":			System.out.println("今天是周二");			break;		case "周三":			System.out.println("今天是周三");			break;		case "周四":			System.out.println("今天是周四");			break;		case "周五":			System.out.println("今天是周五");			break;		case "周六":			System.out.println("今天是周六");			break;		case "周日":			System.out.println("今天是周日");			break;		default:			break;		}	}}

有关枚举类型,我们将会在后续的内容中学习,此处不做过多解释。

3.2.3 分支嵌套

如果把一个分支结构放进另一个分支结构中,这种情况叫做分支嵌套,分支嵌套可以是if中嵌套switch,switch中嵌套if,也可以是if互相嵌套或者switch自身嵌套。例如,计算一个年份是否是闰年。

package cn.bytecollege;import java.util.Scanner;/** * 本例将演示输入一个年份 * 判断是否是闰年 * @author MR.W * */public class LeapYear {	public static void main(String[] args) {		System.out.println("请输入年份:");		Scanner scanner = new Scanner(System.in);		int year = scanner.nextInt();				if(year%4==0) {			if(year%100==0) {				if(year%400==0) {					System.out.println(year+"是闰年");				}else {					System.out.println(year+"不是闰年");				}			}else {				System.out.println(year+"是闰年");			}		}else {			System.out.println(year+"不是闰年");		}	}}

3.3 循环结构

循环结构是指在满足某个循环条件的情况下,反复执行同一段代码,直到不满足循环条件为止。被循环执行的代码叫做循环体。当反复执行循环体时,要在适当的时机修改循环条件,从而结束循环,否则循环会一直进行下去,形成死循环。一个恰当的循环结构应该包含以下4个组成部分:

  1. 初始化语句:一个或多个语句,这些语句用来完成一些初始化工作,在循环开始之前执行

  2. 循环条件:循环条件是一个布尔表达式,该表达式决定是否执行循环体

  3. 循环体:这部分是循环的主题,如果循环条件允许,该代码块将被反复执行,如果这个代码块只有一条语句,则代码块的花括号可以省略。

  4. 迭代语句:这部分在一次循环体执行结束后执行,在循环条件求值前执行,通常用于控制循环条件中的变量,使得循环在合适的时候结束。

3.3.1 for循环

for循环是循环结构中常用的一中,其语法格式如下:

for([init_statment];[test_exression];[iteration_statement]){    statement;   }

其中init_statment指初始化条件,test_expression指循环条件,statement是指循环体,iteration_statement是指迭代语句,在statement执行结束以后执行。程序执行for循环时,先执行init_statment,初始化语句只在循环条件开始前执行1次,每次执行循环体之前,先计算

test_exression循环条件的值,如果循环条件返回为true,则执行循环体,循环体执行结束后执行循环迭代语句。因此对于for循环而言,循环条件总比循环体要多执行1次,因为最后1次执行循环条件返回false,将不再执行循环体。

下面,我们通过示例来学习for循环,通过本示例,我们计算1-100的和

package cn.bytecollege;/** * 本示例将演示for循环 * @author MR.W * */public class ForDemo {	public static void main(String[] args) {		//定义变量保存结果		int sum= 0;		for (int i = 1;i<=100;i++) {			sum += i;		}		System.out.println(sum);	}}

在上例中int sum = 0是指定义1个变量,用于保存最后的结果,for循环则是定义了一个循环结构。

在for循环中int i =1定义了初始化语句,i<=100则是循环条件,当i的值是101的时候该表达式返回false则终止循环,sum+=i等价于sun=sum+i是循环体,用于累加值,i++则是用于改变循环变量的值,递增循环变量的值。下面我们来分析这段代码的执行过程:

  1. 当i = 1时,此时先判断循环条件是否成立,i<=100返回值为true。

  2. 循环条件成立,则进入循环体,此时sum= 0,sum = sum+i运算后sum的值变为1

  3. 循环体执行结束后,改变循环变量的值i的值为2

  4. 此时再次判断循环条件,2<=100成立,因此再次进入循环,执行2直至条件不成立为止

注意:除非特殊情况尽量不要在循环体内修改循环变量的值。

此外,需要注意的是for循环圆括号中只有两个分号是必须的,初始化语句、循环条件、迭代语句部分都是可以省略的,如果省略了循环条件,则这个循环条件默认为true,将会产生死循环。例如下面的代码。

package cn.bytecollege;/** * 本例将演示死循环 * @author MR.W * */public class EndlessForLoop {	public static void main(String[] args) {		for (;;) {			System.out.println("-----endless-----");		}	}}

运行上例中的代码,会发现程序一直输出"-----endless-----",表明此程序是一个是损坏。

在使用for循环时,初始化条件不需要一定要定义在for循环括号中,也可以定义在循环外。如下例所示:

package cn.bytecollege;/** * 本示例将演示for循环 * @author MR.W * */public class ForDemo {	public static void main(String[] args) {		//定义变量保存结果		int sum= 0;		int i = 1;		for (;i<=100;i++) {			sum += i;		}		System.out.println(sum);	}}

3.3.3 while循环

while循环的语法格式如下:

[init_statement]while(test_expression){	statement;    [iteration_statment]}

while循环每次执行循环体之前,先对test_expression循环条件求值,如果循环条件为true,则执行循环体部分。从上述伪代码中来看,iteration_statment位于循环体的最后,因此只有当循环体成功执行完成是,while循环才会执行iteration_statment语句。

下面,我们通过示例学习while循环:

package cn.bytecollege;/** * 本例将演示while循环 * @author MR.W * */public class WhileDemo {	public static void main(String[] args) {		int i = 1;		int sum = 0;		while(i<=100) {			sum+=i;			i++;		}		System.out.println(sum);	}}

如果while循环的循环体部分和迭代语句合并在一起,且只有一行代码,则可以省略。但是通常不建议省略。

使用while循环是,一定要保证循环条件有变成false的时候,否则这个循环将变成死循环,用于无法结束循环。如下例所示:

package cn.bytecollege;/** * 本例将演示while死循环 * @author MR.W * */public class EndlessWhileLoop {	public static void main(String[] args) {		int count = 0;		while(count < 5) {			System.out.println("进入死循环");			count --;		}		System.out.println("无法跳出循环体");	}}

上面的示例中,count的值越来越小,小于5用于成立,循环条件一直为true,从而导致这个循环永远无法结束。

3.3.4 do while循环

do while循环与while循环的区别在于:while循环是先判断循环条件,如果条件为真则执行循环体;而do while循环则新执行循环体,然后才判断循环条件,如果循环条件为真,则执行下一次循环,否则终止循环。do while循环语法格式如下:

[init_statement]do{	statement;    [iteration_statment]}while(test_expression);

注意:do while循环的循环条件必须有一个分号,该分号代表该循环结构结束。

下面我们通过示例示范do while循环的用法

package cn.bytecollege;/** * 本示例将演示dowhile循环用法 * @author MR.W * */public class DoWhileDemo {	public static void main(String[] args) {		int sum = 0;		int i = 1;		do {			sum += i;			i++;		}while(i<=100);		System.out.println(sum);	}}

需要注意的是,即便此时循环条件的开始值为false,dowhile循环体也会执行1次,因此do while的循环体至少执行1次,而while循环的循环条件执行1次。下面我们通过示例来演示:

package cn.bytecollege;/** * 本例将演示while和dowhile的区别 * @author MR.W * */public class WhileAndDoWhile {	public static void main(String[] args) {				int i = 0;		int k = 0;		while (++i>1) {			System.out.println("循环条件至少执行1次");		}		System.out.println(i);		do {			k++;		}while(false);				System.out.println(k);			}}

从上例中可以看出,++i=1执行后i的值为1,此时该表达式结果为false,不执行循环体,而do while循环中循环条件直接是false,但是此时仍旧执行了循环体,k的值成为了1。

4.控制循环结构

在C语言中提供了goto语句控制程序的跳转,但是Java中goto只作为了保留字,而没有提供该语句,这种做法提高了程序流程控制的可读性,但是降低了程序流程控制的灵活性。为了弥补此处的不足,Java提供了continue和break控制循环结构。

4.1 使用break结束循环

在某些特定的条件下我们需要强制终止循环,而不是等到循环条件为false时才退出循环。此时可以使用break来完成这个功能。break用于完全结束一个循环,跳出循环体,不管是哪种循环,一旦循环体中遇到break,系统将完全结束该循环,开始执行循环结构以后的代码。例如下列示例:

package cn.bytecollege;/** * 本例将演示break * @author MR.W * */public class BreakDemo {	public static void main(String[] args) {		for (int i = 0; i < 10; i++) {			if(i==7) {                System.out.println(i);				break;			}		}	}}

上例代码将循环打印0-6,当变量i的值变为7的时候,满足if条件判断,此时进入if分支结构,进入以后遇到break,此时跳出循环。

因此,break可以视为中断循环,及时循环还没有结束,也再不循环,直接结束,当然break也可以跳出多层循环,跳出多层循环我们将在下一节进行讲解。

4.2 使用continue跳过此次循环

continue的功能和break有点类似,区别是continue只是跳出此次循环,继续执行剩下的循环,并不是完全终止循环。下面我们通过示例学习:

package cn.bytecollege;/** * 本例将演示continue * @author MR.W * */public class ContinueDemo {	public static void main(String[] args) {		for (int i = 0; i < 10; i++) {			if(i==7) {				continue;			}			System.out.println(i);		}	}}

我们将break换成continue,运行程序我们发现程序打印了0-6,8-9,这说明程序并没有完全退出,只是i==7时忽略了此次循环,继续执行剩下的循环。

5.循环嵌套

如果把一个循环放进另一个循环体内,那么就可以形成循环嵌套,循环嵌套可以是上述3种循环的任意嵌套,例如:for循环和while循环的相互嵌套,while循环和do while循环的相互嵌套,也可以是while循环和do while循环的相互嵌套。

当程序遇到循环嵌套是,如果外层循环的循环条件允许,则开始执行外层循环的循环体,而内层循环将被外层循环的循环体来执行,只是内层循环需要反复执行自己的循环体而已。当内层循环执行结束,且完成循环的循环体执行结束时,在再次计算外层循环的循环条件,决定是否再次执行外层循环的循环体。下面我们通过示例来学习。

示例:打印如下图形:

**



通过分析我们可以发现我们需要两个循环其中外层控制打印的行数,而内层循环则用来控制打印*的个数。

package cn.bytecollege;/** * 本例将演示打印* * @author MR.W * */public class PrintDemo {	public static void main(String[] args) {		for (int i = 1; i < 4; i++) {			for (int j = 0; j < i; j++) {				System.out.print("*");			}			System.out.println();		}	}}	

在上例中,当外层i =1时,满足外层循环的循环条件,因此进入循环体,而内层循环则是外层循环的循环体,此时j = 0,并且满足循环条件,执行循环体,打印1一个*,改变循环变量j的值后j<i返回值为false,此时内层循环结束,并换行,此时改变外层循环的循环变量i,继续执行重复以上步骤。

5.1 循环嵌套中的break

break语句仅结束其所在的循环,例如在双层循环嵌套中,只结束内层循环,而不能结束外层循环。下面我们通过示例来学习。

package cn.bytecollege;/** * 本例将演示break跳出自身所在循环 * @author MR.W * */public class BreakDemo2 {	public static void main(String[] args) {				for (int i = 0; i < 10; i++) {			for (int j = 0; j < 5; j++) {				if(j==2) {					break;				}				System.out.println("内存循环:"+j);			}			System.out.println("外存循环:"+i);		}			}}

运行上述代码,我们可以发现break只是结束了内层自己所在的循环,外层循环并没有被结束,仍旧在继续循环。

img

那么, 如何让break结束外层循环呢,此时就要在break后面紧跟一个标签了,这个标签用于表示一个外层循环。

Java中的标签就是一个紧跟着因为冒号的标识符,与其他语言不同的是,Java中的标签只有放在循环语句前才有作用。

package cn.bytecollege;/** * 本例将演示循环嵌套中break结束外层循环 * @author MR.W * */public class BreakDemo3 {	public static void main(String[] args) {		outer:		for (int i = 0; i < 5; i++) {			//内层循环			for (int j = 0; j < 3; j++) {				if(j==1) {					//跳出outer所标识的循环					break outer;				}				System.out.println("i的值为:"+i+",j的值为:"+j);			}		}	}}	

运行上面的代码,看到如下运行结果:

img

程序从外层循环进入内层循环,当j等于1时,程序遇到一个break outer语言,该语句将会导致结束outer标签指定的循环,不是break所在的循环,而是结束break循环的外层循环。

需要注意的是,break后的标签必须是一个有效的标签,这个标签必须在break语句所在的循环之前定义,或者在所在循环的外层循环之前定义。当然,如果把这个标签放在break语句所在的循环之前定义,也就失去了标签的意义,因为break默认就是结束其所在的循环。

5.2 循环嵌套中使用continue

同样,我们可以将上例中break换成continue,此处continue的作用不变,只是在多层循环中,continue会忽略当前循环,直接到外层循环继续进行循环

package cn.bytecollege;/** * 本例将演示多层循环嵌套中使用Continue * @author MR.W * */public class ContinueDemo2 {	public static void main(String[] args) {		outer:		for (int i = 0; i < 5; i++) {			//内层循环			for (int j = 0; j < 3; j++) {				if(j==1) {					//跳出outer所标识的循环					continue outer;				}				System.out.println("i的值为:"+i+",j的值为:"+j);			}		}	}}

img

根据运行结果可以看到内层循环当执行到j==1时,此时继续执行外层循环。需要注意的是,除非特殊情况,一般情况下我们并不使用这种方式来控制循环。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值