← Java 基础教程

第 7 / 40 课 · 免费教程

天黑了,if 还是 else

让程序根据条件选择行动

90–110 分钟Java 11+入门 · 条件判断

本课作品

制作夜间生存顾问

从一扇条件门走到一条完整决策链:分清多条提醒与一条主建议,用边界值检查规则,最后完成能听懂回答的夜间生存顾问。

开始前:建议先完成第 1–6 课

01 / 15

一扇没有墙的门

太阳刚躲到山后,史蒂夫便把门插在草地上:“安全屋,完工!”Alex 指指门两边:“墙呢?”一只僵尸绕过门走来,仿佛在称赞这座房子的通风设计。

程序也需要明确的门槛。天黑时做什么,生命低时做什么,两件事同时发生时先做什么?这一课,我们把含糊的“看情况”写成可以检查的规则。

  • if 的条件成立时,哪些语句会执行?
  • 提醒缺少的所有装备,与只选一个优先动作,写法相同吗?
  • 生命恰好为0、8、9时,结果为什么不同?

02 / 15

if:条件成立才行动

if 可以读作“如果”。圆括号里必须得到 boolean 值,花括号圈住条件成立时要做的事。程序执行到这里才判断一次;变量以后变化,不会让这段代码自动重演。

完整程序:保存为 HealthAlert.java

public class HealthAlert {
    public static void main(String[] args) {
        int health = 7;
        if (health <= 8) {
            System.out.println("先补给");
        }
        System.out.println("检查结束");
    }
}

运行结果

先补给
检查结束
条件门:两条路最后会合

health <= 8 ?

条件结果执行路径
true输出“先补给”
false跳过补给语句

↓ 两条路都输出“检查结束”

03 / 15

else:否则走另一条路

想让条件不成立时也做一件事,就加上 else。同一次 if / else 判断只走一边,像矿车过岔道,不会复制出另一辆自己。

片段:放在 main 中,单独运行

boolean isNight = true;
if (isNight) {
    System.out.println("回屋休整");
} else {
    System.out.println("白天采集");
}

运行结果

回屋休整

片段:放在 main 中,单独运行

int diamonds = 2;
if (diamonds >= 3) {
    System.out.println("钻石数量够了");
} else {
    System.out.println("还差" + (3 - diamonds) + "颗钻石");
}

运行结果

还差1颗钻石

04 / 15

else if:顺序也是规则

一条分支链从上往下检查,选中第一个条件为真的分支,后面的分支便不再检查。先处理更紧急、更具体的情况,别让一个宽条件吞掉后面的窄条件。

片段:放在 main 中,单独运行

int health = 7;
if (health <= 0) {
    System.out.println("重生");
} else if (health <= 8) {
    System.out.println("快吃东西");
} else {
    System.out.println("继续冒险");
}

运行结果

快吃东西
只选一条:从上往下找入口
按顺序检查命中后执行
health <= 0 ?重生
health <= 8 ?快吃东西
else继续冒险

从上往下检查;只执行首个匹配的分支。

05 / 15

把小条件拼成大问题

先用一句话讲清楚条件
  1. && 并且两项都满足:天黑并且没有住所。
  2. || 或者至少一项满足:有钥匙或者是主人。
  3. ! 取反把真假翻过来:!hasShelter 表示没有住所。

片段:放在 main 中,单独运行

boolean isNight = true, hasShelter = false;
if (isNight && !hasShelter) {
    System.out.println("先建临时住所");
}

运行结果

先建临时住所

片段:放在 main 中,单独运行

boolean hasKey = false, isOwner = true;
if (hasKey || isOwner) {
    System.out.println("门开了");
}

运行结果

门开了

片段:放在 main 中,单独运行

String weather = " RAIN ".strip();
if ("rain".equalsIgnoreCase(weather)) {
    System.out.println("把施工计划挪到屋内");
}

运行结果

把施工计划挪到屋内

06 / 15

多条提醒,还是一条主建议?

缺面包也缺盾牌,可以提醒两件事;决定“现在先做什么”,则可能只需要一句主建议。先确定任务,再选择独立 if 或分支链。

片段:放在 main 中,单独运行

int health = 6;
if (health <= 8) {
    System.out.println("带面包");
}
if (health <= 16) {
    System.out.println("带盾牌");
}

运行结果

带面包
带盾牌

片段:放在 main 中,单独运行

int health = 6;
if (health <= 8) {
    System.out.println("带面包");
} else if (health <= 16) {
    System.out.println("带盾牌");
}

运行结果

带面包
条件相同,组织方式不同
  1. 两个独立 if两个条件各查一次,可能输出两条提醒。
  2. 一条 if / else if 链选中前一条后,不再检查后面的条件。

07 / 15

Bug 最爱坐在门槛上

7能正确运行,不代表8也正确。先规定生命的合法范围,再把它分成没有遗漏、不会重复命中的几档。每个门槛都测试它自己和两边的邻居。

片段:放在 main 中,单独运行

int health = 8;
if (health < 0 || health > 20) {
    System.out.println("生命范围错误");
} else if (health == 0) {
    System.out.println("重生");
} else if (health <= 8) {
    System.out.println("低生命");
} else if (health <= 16) {
    System.out.println("谨慎前进");
} else {
    System.out.println("生命充足");
}

运行结果

低生命
生命分档:把测试点写在规则旁
输入范围本课结果代表测试值
范围外生命范围错误-1、21
0重生0
1到8低生命1、8
9到16谨慎前进9、16
17到20生命充足17、20

08 / 15

嵌套:进村后再找房间

先问是不是夜晚,再在夜晚分支里问有没有住所,这就是嵌套。缩进帮我们看层次,花括号才真正决定哪些语句属于哪一层。

片段:放在 main 中,单独运行

boolean isNight = true, hasShelter = false;
if (isNight) {
    if (hasShelter) {
        System.out.println("回屋休整");
    } else {
        System.out.println("先建临时住所");
    }
} else {
    System.out.println("白天采集");
}

运行结果

先建临时住所

片段:放在 main 中,单独运行

boolean isNight = false;
String advice;
if (isNight) {
    advice = "回家";
} else {
    advice = "采集";
}
System.out.println(advice);

运行结果

采集

09 / 15

能运行,也可能判断错

逻辑反例:先预测,再找多余符号

boolean isNight = false;
if (isNight); { // 错误示范:多了分号
    System.out.println("关门");
}

运行结果

关门

分号是一条空语句。这里 if 只控制这条空语句,后面的代码块独立执行;删掉条件后的分号才能修好。

逻辑反例:钥匙被程序偷偷改了

boolean hasKey = false;
if (hasKey = true) { // 错误示范:赋值,不是比较
    System.out.println("开门");
}

运行结果

开门

boolean 赋值也会产生 boolean 结果,因此这个错误竟然能编译。改成 if (hasKey) 就够了;若写 if (health = 8),得到的是 int,则不能作为条件。

  • 核对花括号,避免 else 配错 if。
  • 核对 = 与 ==,不要把赋值当成比较。
  • 核对 < 与 <=,用恰好等于门槛的值测试。

10 / 15

先猜,再跑,最后解释

让每次运行都留下思考
  1. 先猜写下输出与会命中的分支。
  2. 再跑只运行当前片段,核对每一行。
  3. 解释指出哪次判断改变了路线。

片段:放在 main 中,单独运行

int diamonds = 3, sticks = 1;
if (diamonds >= 3 && sticks >= 2) {
    System.out.println("材料齐了");
} else {
    System.out.println("材料还不齐");
}

片段:放在 main 中,单独运行

int health = 8;
if (health <= 8) {
    health += 2;
}
if (health > 8) {
    health += 1;
}
System.out.println(health);

核对答案

第一题输出“材料还不齐”,因为木棍只有1根。第二题输出11:第一次把8变成10,第二个独立 if 读到新值10,又加1。

11 / 15

项目蓝图:夜间生存顾问

“别在我生命为0时推荐装修。”史蒂夫的需求很合理。这个顾问每次读三行输入,只给一条主建议;要再次询问,就重新运行程序。

先验输入,再作决定
  1. 读整行生命、时段、住所,先 strip。
  2. 检查选项时段 day/night,住所 yes/no。
  3. 解析数字parseInt 与 catch,随后查范围。
主建议优先级:前面选中就停止向下检查
按顺序检查命中后执行
合法生命 == 0准备重生
合法生命 <= 8先到安全处补给
生命9到20再看时段与住所

从上往下检查;只执行首个匹配的分支。

12 / 15

顾问代码:读取与验证

新建 NightAdvisor.java。完整程序印在本页和下一页:按顺序连在同一个文件内,不要在两页之间额外添加花括号。

NightAdvisor.java · 上半部分,下一页继续

import java.util.Scanner;

public class NightAdvisor {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        System.out.println("生命 0-20:");
        String healthText = in.nextLine().strip();
        System.out.println("时段 day/night:");
        String time = in.nextLine().strip();
        System.out.println("有住所 yes/no:");
        String home = in.nextLine().strip();
        boolean timeOK = "day".equalsIgnoreCase(time)
                || "night".equalsIgnoreCase(time);
        boolean homeOK = "yes".equalsIgnoreCase(home)
                || "no".equalsIgnoreCase(home);
        if (!timeOK || !homeOK) {
            System.out.println("选项有误,请检查时段和住所");
        } else {
            try {
                int health = Integer.parseInt(healthText);
                boolean isNight = "night".equalsIgnoreCase(time);
                boolean hasShelter = "yes".equalsIgnoreCase(home);

三个输入都用 nextLine 读取,避免混用 nextInt 时留下行尾。timeOK 与 homeOK 先确认词语合法;通过后才把 night、yes 转成 true。

13 / 15

顾问代码:选择与收尾

NightAdvisor.java · 紧接上一页

                if (health < 0 || health > 20) {
                    System.out.println("生命必须在0到20之间");
                } else if (health == 0) {
                    System.out.println("生命耗尽,准备重生");
                } else if (health <= 8) {
                    System.out.println("先到安全处补给");
                } else if (isNight) {
                    if (hasShelter) {
                        System.out.println("回屋休整");
                    } else {
                        System.out.println("先建临时住所");
                    }
                } else {
                    System.out.println("白天采集,别忘带补给");
                }
            } catch (NumberFormatException e) {
                System.out.println("生命请输入0到20的整数");
            }
        }
    }
}

try/catch 沿用第6课的解析方法。若输入 abc、小数或装不进 int 的大数,catch 给出整数提示。输入合法后,这条分支链只会输出一条主建议。

14 / 15

验收:一次只改一个输入

只动一个变量,观察路线变化
  1. 8 / night / yes先到安全处补给
  2. 9 / night / yes回屋休整
  3. 9 / night / no先建临时住所
顾问测试表
生命 / 时段 / 住所预期主结果
0 / day / yes生命耗尽,准备重生
20 / day / no白天采集,别忘带补给
-1或21 / day / yes生命必须在0到20之间
abc、8.5或过大整数 / day / yes生命请输入0到20的整数
9 / nite / yes选项有误,请检查时段和住所
9 / night / maybe选项有误,请检查时段和住所

让测试成为证据

  • 再测1、8、9、20,确认每条主建议都被访问。
  • 试两端空白和大写 NIGHT / YES,确认清理与忽略大小写生效。
  • 生命和选项同时错误时,按约定先报告选项错误。
  • 每行记录输入、预测、实际结果和差异原因。

15 / 15

把判断技能装进背包

木镐任务:钻石数量检查

先用变量,再接键盘输入。负数报错,至少3颗报告够用,否则算还差多少。测试-1、0、2、3、4;2应差1颗。

铁镐任务:生命四档广播

范围限定0到20,分成0、1到8、9到16、17到20,只输出一个档位。用九个边界测试值核对,并解释最后 else 为什么只剩最后一档。

钻石镐任务:天气与装备顾问

读取 clear、rain、thunder 与 yes/no。先验证,再处理雷雨与住所,最后才给普通天气建议。增加护甲条件时,先写清优先级,至少测试6组。

技术核对:Oracle Java 语言规范第14章,if、代码块与局部变量。
https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html

TAKE IT WITH YOU

下载本课 PDF

完整课文、代码、图解与练习,选择你需要的语言。