分支结构
1. 第一个分支结构的例子
程序经常需要在不同的情况下选择做不同的事情,比如
用户输入一个数,判断是不是偶数,并给出相应结论。
Guidelines.
- 右键单击
src
,新建一个包,起名为flowcontrol
: new -> Package -> 填入包名flowcontrol,确定; - 右键单击包
flowcontrol
,new -> Class -> 填入类名CheckEvenNumber, 确定。
例1. 判断输入的整数是奇数还是偶数
CheckEvenNumber.java
package flowcontrol; // 申明该类所在的包
import java.util.Scanner; // 引入java提供的用于console输入的类:Scanner
public class CheckEvenNumber {
public static void main(String[] args) {
// 用Scanner类创建一个对象,用来捕获输入,System.in是通过console输入
Scanner input = new Scanner(System.in);
System.out.print("Enter a number: "); // 输出一个提示
// 读入一个整数,这里java已经自动将输入转化为整数
int num = input.nextInt();
input.close(); // 关闭input对象
if (num % 2 == 0) { // 如果输入的数字是个偶数(可以被2整除),执行{}里的代码
System.out.println(num + " is even.");
} else { // 否则, otherwise,执行{}内的代码
System.out.println(num + " is odd.");
}
}
}
在上面的例子中,我们引入了一些新的概念:
- 包(
Package
):类似于文件夹,用来将类(class
)分类存放。如果一个类属于一个包,那么这个类的开头必须声明, 在src
根目录下的类不需要申明其所属包。上面的例子中,CheckEvenNumber.java
是放在flowcontrol
包里的,那么在类的开头需要声明:package flowcontrol;
- 引入其他类:通常我们需要使用其他类和它提供的方法(比如Java自带的方法Math类和其提供的方法Math.sqrt()用来计算平方根),在使用之前需要先引入这个类,比如这个例子中的:'
import java.util.Scanner;
' 申明将Java
提供的捕获输入的类引入到CheckEvenNumber.java
类中使用。
该例子的核心内容是这一片代码
if (num % 2 == 0) { // 如果输入的数字是个偶数(可以被2整除),执行{}里的代码
System.out.println(num + " is even.");
} else { // 否则, otherwise,执行{}内的代码
System.out.println(num + " is odd.");
}
这里的if else
代码块
if (关系表达式){
代码块1;
} else {
代码块2;
}
就是一个分支结构, 其表示:
- 如果关系表达式为
true
,那么执行代码块1;- 否则执行代码块2.
- 例子中关系表达式
num % 2 == 0
是先计算num % 2
的结果,然后判断其结果是否等于0.
Tips.
- 关系表达式有
a>b, a<b, a==b, a!=b, a>=b, a<=b
等均是关系运算,结果是true
或者false
;- 判断两个数是否相等是
==
,=
是赋值。判断两个是是否不等是!=
。- 关系运算的优先级在数学运算之下,Java会先计算关系运算符(>, <,==等)两边的结果,再进行关系判断。
Extension:构建一个方法,将判断奇偶的任务分配出去
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Enter a number: ");
int num = input.nextInt();
input.close();
checkEvenNumber(num);
}
static void checkEvenNumber(int aNum) {
if (aNum % 2 == 0) {
System.out.println(aNum + " is even.");
} else {
System.out.println(aNum + " is odd.");
}
}
extension中构建了一个方法checkEvenNumber(int aNum)
, 需要一个int
类型的参数(需要判断的数)。在main
方法中调用这个方法并传入console
输入的数进行判断。
2. 分支结构和流程图
我们可以用程序流程图(flow chart)来描述以上分支结构,流程图在程序设计的时候也很有用。一个基本的包含if
和else
statement的流程图如下:
图1. if-else分支结构流程图
例1就是一个同时包含if
和else
的分支结构程序。
在一些情况下,可能只存在if
代码块,而不存在else
代码块:如果条件成立,就做点事情;要是不成立就算了。比如:
例2. 检查是否是VIP
模拟用户登陆后,判断是否是VIP:
- 如果是则显示欢迎VIP的信息(同时可以赋予VIP权限);
- 如果不是此处不做任何处理。
Guidlines.
- 右键单击flowcontrol包,包名设置为
flowcontrol.vip
- 右键单击
flowcontrol.vip
包,新建一个class,命名为CheckVIP。
Tips.
Java中包和子包(文件夹和子文件夹)的关系是用"."来描述的,
flowcontrol.vip
是说在flowcontrol
包下建立一个子包,命名为vip
。
CheckVIP.java
package flowcontrol.vip;
public class CheckVIP {
public static void main(String[] args) {
String username = "customer_1";
boolean isVIP = checkVIP(username); // 调用检验VIP的方法
if(isVIP) {
System.out.printf("Welcome back, VIP user %s \n\n", username);
// 实际中这里可以给VIP用户授与使用VIP服务的权限
}
System.out.println("Display the personal page for the user.");
}
static boolean checkVIP(String uname) {
boolean isVIP = true; // 实际中可以通过传入的参数uname从数据库获取
return isVIP; // 返回是否是VIP的信息
}
}
程序说明:
- 实际检验是否是VIP的工作交给了方法
checkVIP(String uname)
去实现; - 在
main
方法中,调用这个方法,获取是否是VIP的信息(true
或者false
),然后赋值给main
方法的局部变量isVIP
; - 如果
isVIP
等于true
,则打印欢迎信息; 如果isVIP
等于false
,则跳过if
后面{ }
代码块的内容。 - 继续执行后续程序。
其对应的流程图为:
图2. 只有if statement的分支结构
3. 链式分支 & 嵌套分支结构:Lucky Draw的例子
玩一个Lucky Draw的游戏:
分一等奖,二等奖和不中奖。一等奖中奖概率10%, 二等奖40%,三等奖50%;
设计一个程序,来实现这个lucky draw的游戏。
3.1 链式分支的方案
Guidelines.
右键单击包
flowcontrol
,创建一个名为luckydraw
的包; 右键单击这个包,创建一个类:new -> Class -> 填入类名LuckyDraw01, 确定。
例3. 链式分支结构的LuckyDraw
LuckyDraw01.java
package flowcontrol.luckydraw;
import java.util.Random;
public class LuckyDraw01 {
static final firstPrizeProb = 0.1; // 中一等奖概率,小于这个概率的中奖
static double secondPrizeProb = 0.3; // 中二等奖概率,小于这个概率且大于一等奖概率的中奖
public static void main(String[] args) {
// 用Java提供的Random类,创建一个叫randomNumGenerator的对象,用来产生随机数
Random randomNumGenerator = new Random();
// 生成一个double类型的随机数,保存到youDraw变量里
double yourDraw = randomNumGenerator.nextDouble();
// 显示随机数。%.2f 为有‘两位小数’的小数占位符
System.out.printf("Your draw is %.2f. \n", yourDraw);
if(yourDraw < firstPrizeProb) {
System.out.println("Congratulations! You won the first prize!");
} else if(yourDraw < firstPrizeProb + secondPrizeProb){
System.out.println("You won the second prize!");
} else {
System.out.println("Oops! What a bad luck.");
}
}
}
上面例子中判断中几等奖的代码结构是
if(condition 1) {
代码块1;
} else if(condition 2) {
代码块2;
} else {
代码块3;
}
说明:
- 如果
condition 1
为true
,则执行代码块1
; - 否则,继续判断
condition 2
, 如果condition 2
为true
,则执行代码块2
; - 否则执行
代码块3
.
上面的例子中,把0-1
的数分成了三段:0~0.1
, 0.1~0.5
, 其他。当(0到1以内的)随机数落在0~0.1
是一等奖,落在0.1~0.5
是二等奖,否则不得奖。很直观,上述程序满足对中奖概率的要求。
3.1 嵌套分支的方案
上面例子中分支部分可以更改为:
例4. 嵌套分支结构的LuckyDraw
if (yourDraw > 1 - firstPrizeProb - secondPrizeProb) { // 未获奖
System.out.println("Oops! What a bad luck.");
} else { // 否则,即获奖,再在内层if-else判断获几等奖
if(yourDraw < firstPrizeProb) { // 获得一等奖
System.out.println("Congratulations! You won the first prize!");
} else {
System.out.println("You won the second prize!");
}
}
以上例子的代码结构为
if (condition 1) {
外层代码块1;
} else {
//内层if-else代码块
if (condition 2) {
内层代码块1;
} else {
内层代码块2;
}
}
Tips.
因为{ }
是包围一个相对完整的代码块,所以里面包含什么结构都不奇怪。