2.1. 条件与重复动作¶
2.1.1. 选择¶
我们迄今为止编写的方法具有一个共同特征——顺序执行。顺序执行意味着语句按照它们在源代码中出现的顺序依次执行。在本章中,我们将学习如何创建一块可以执行或跳过的语句块,以及如何选择在多个替代语句块中执行其中一个。
控制结构 是编程语言的一种特性,用于决定语句的执行顺序。控制结构分为三类:(1) 顺序结构,(2) 选择结构,以及 (3) 重复结构(也称为循环)。
顺序结构是大多数面向对象编程语言默认使用的结构:将语句一条接一条地按顺序排列。除非另有说明,否则语句将按照它们在源代码中出现的顺序执行,且每条语句恰好执行一次。我们迄今为止看到的每个程序都只使用了顺序结构。
条件 是选择结构和循环结构的关键组成部分。条件是任何可以为真或假的表达式。
备注
条件 是任何可以为真或假的表达式。
每个 选择结构 都定义了两条或多条穿过源代码的备选路径。有三种重要的选择结构:if-then-else 结构、if-then 结构和多路分支结构。
if-then-else 结构(有时称为 if-else 结构)是最基本的选择结构,因为它可以用于形成任何可能的选择模式。if-then-else 结构定义了两个不同的语句块,其中只有一个会被执行。
if-then 结构(有时简称为 if 结构)是 if-then-else 的一种特殊形式,其中只提供一个语句块,而省略第二个语句块。因此,if-then 结构定义了一个可选的语句块,该块要么被执行,要么被跳过。
多路条件 结构(有时称为多路分支结构)定义了多个不同的语句块,其中只有一个会被执行。Java 还有一个 switch 结构用于创建多路分支结构,但我们稍后再学习它。
2.1.2. 使用传感器方法的条件¶
Jeroo 类提供了若干 传感器方法,可用于询问 Jeroo 关于其周围环境的情况。每个传感器方法的返回结果为真或假。任何返回结果为真或假的方法称为 布尔方法 (也称为 谓词)。更一般地,任何结果为真或假的表达式称为 boolean 表达式(以 George Boole 命名)。这意味着在各种控制结构中使用的条件实际上是 boolean 表达式。
备注
任何产生真或假结果的方法都被称为 布尔方法 (也称为 谓词)。
对于 Jeroo,传感器方法是构建条件的基本模块。创建条件的最简单方式是调用传感器方法。下表列出了 Jeroo 类提供的所有传感器方法。这些方法仅可用于构造条件。由于它们是方法,因此需要通过向 Jeroo 对象发送消息来调用。
方法 |
目的 |
示例 |
|---|---|---|
|
这只 Jeroo 有花吗? |
|
|
指定方向是否有空地?空地是指没有花、没有网、没有水且没有 Jeroo 的空间。[ |
|
|
这只 Jeroo 是否朝向指定方向? |
|
|
指定方向是否有花? |
|
|
指定方向是否有另一只 Jeroo?[ |
|
|
指定方向是否有网?[ |
|
|
指定方向是否有水?[ |
|
值得注意的是,当你看到 relativeDirection 时,你的方向选择包括 HERE 、 LEFT 、 RIGHT 和 AHEAD 。当你看到 compassDirection 时,你的方向选择为: NORTH 、 SOUTH 、 EAST 和 WEST 。
2.1.3. 条件语句概述¶
2.1.4. Java 中 if-then-else 结构的语法¶
该图展示了 Java 中 if-then-else 结构的语法。关于该语法,有四点需要特别注意。
条件 必须 放在括号中。
括号后 没有分号。
关键字
else后没有分号。if-then-else 结构不是一个方法,这意味着我们不会将其作为消息发送给 Jeroo 对象。
关于编码风格,有三点需要特别注意。
花括号用于定义真分支和假分支的起始与结束。务必包含它们。
花括号与单词
if和else的起始位置对齐。花括号之间的语句应缩进(我们使用 4 个空格)。
2.1.4.1. 示例(if-then-else 结构)¶
让名为 Timmy 的 Jeroo 检查正前方是否有网。如果有,让他禁用该网并转身。如果正前方没有网,Timmy 应向右转。在他禁用网并转身或仅仅向右转之后,Timmy 必须向前移动一格。
if (timmy.seesNet(AHEAD))
{
timmy.toss();
timmy.turn(LEFT);
timmy.turn(LEFT);
}
else
{
timmy.turn(RIGHT);
}
timmy.hop();
2.1.4.2. 自测¶
2.1.5. 语法练习 3a:If-Then-Else¶
2.1.6. 使用 If-then 创建可选语句¶
if-then 结构(有时称为 if 结构)定义了一个可选的语句块。if-then 结构只是一个省略了第二个语句块(即 else 部分)的 if-then-else 结构,因此选择变为执行第一个语句块 或跳过它。
if 结构包含两部分:选择条件和真分支。真分支包含一组语句,仅当选择条件为真时才会执行。
上图展示了一个通用的 if-then 结构,并使用箭头指示语句的执行顺序。if 结构定义了可选代码,该代码要么被跳过,要么仅执行一次。
2.1.7. Java 中 if-then 结构的语法¶
该图展示了 Java 中 if-then 结构的语法。关于该语法,有三点需要特别注意。
条件 必须 放在括号中。
括号后 没有分号。
if-then 结构不是方法,这意味着我们不会将其作为消息发送给 Jeroo 对象。
关于编码风格,有三点需要特别注意。
花括号用于定义真分支的起始与结束。务必包含它们。
花括号与单词
if的起始位置对齐。花括号之间的语句应缩进(我们使用 4 个空格)。
2.1.7.1. 示例(if-then 结构)¶
让名为 Jessica 的 Jeroo 检查其右侧是否有网。如果有,让她禁用该网并返回当前状态。无论是否禁用了网,Jessica 都应向前跳一格。
if (jessica.seesNet(RIGHT))
{
jessica.turn(RIGHT);
jessica.toss();
jessica.turn(LEFT);
}
jessica.hop();
2.1.7.2. 自测¶
2.1.8. 语法练习 3b:If-Then¶
2.1.9. Java 中多路选择结构(级联 if)的语法¶
此图展示了在 Java 中编写多路选择结构的一种常用技术。从技术上讲,该结构由一系列嵌套的 if-then-else 语句组成,但编码风格掩盖了这一事实,并使多路选择逻辑更加清晰可见。这种特定结构通常称为 级联 if。
关于此结构,有五点重要事项需要观察。
条件 必须 放在括号中。
括号后 没有分号。
else-if 块的数量没有限制。
最终的
else分支是可选的。此结构不是方法,这意味着我们不会将其作为消息发送给 Jeroo 对象。
关于编码风格,有三点需要特别注意。
花括号用于定义真分支的起始和结束。务必包含它们。
花括号与单词
if和else的起始位置对齐。花括号之间的语句应缩进(我们使用 4 个空格)。
2.1.9.1. 示例(多路选择结构)¶
假设有一个名为 Louisa 的 Jeroo,她至少携带一朵花。让她检查前方的单元格。如果该单元格包含一朵花,则采摘它。如果该单元格包含一个网,则禁用它。如果该单元格包含水,则在当前位置种植一朵花。如果该单元格包含另一个 Jeroo,则给那个 Jeroo 一朵花。最后,如果该单元格中没有任何东西,让她向前跳一次并向左转。
if (louisa.seesFlower(AHEAD))
{
louisa.hop();
louisa.pick();
}
else if (louisa.seesNet(AHEAD))
{
louisa.toss();
}
else if (louisa.seesWater(AHEAD))
{
louisa.plant();
}
else if (louisa.seesJeroo(AHEAD))
{
louisa.give(AHEAD);
}
else
{
louisa.hop();
louisa.turn(LEFT);
}
2.1.9.2. 自测¶
2.1.10. 语法练习 3c:多路 If¶
2.1.11. 复合条件¶
条件有两种形式: 简单 条件和 复合 条件。简单条件是一个 boolean 表达式,其中不包含任何其他 boolean 表达式。在 Jeroo 中,简单条件通过调用单个传感器方法形成。 复合条件 则是使用逻辑运算符组合多个条件而创建的。Java 中最常用的三个逻辑运算符是:否定(非)、合取(与)和析取(或)。Java 为每个运算符使用特定的按键输入,如下表所示。
运算符 |
Java 符号 |
含义 |
|---|---|---|
否定 |
|
非 |
合取 |
|
与 |
析取 |
|
或 |
值得注意的是,java 将单个 & 和 | 识别为与 && 和 || 不同的独立运算符(它们与二进制数学有关)。如果你将其中一个误认为另一个,不会抛出错误,你的代码将只是表现得不寻常。此外,! 是一个一元运算符。它可以修改单个 if 语句,但不能将两个合并在一起。
否定运算会反转 布尔 表达式的值,将真变为假、假变为真,如下表所示:
在此表中, P 表示任意布尔表达式。 P 下方的两行显示其可能的取值。第二列显示表达式 !P 的对应取值,其中对布尔表达式应用了非运算符。
合取运算符( && ,表示逻辑与)将两个布尔表达式组合成第三个表达式,仅当原始两个表达式都为真时,该表达式才为真:
在此表中, P 和 Q 代表任意布尔表达式。 P 和 Q 下方的行显示了它们值的所有可能组合。第三列显示了 P && Q 的对应值。
析取运算符( || ,表示逻辑或)将两个布尔表达式组合成第三个表达式,该表达式仅当两个原始表达式均为假时才为假:
在此表中, P 和 Q 再次表示任意布尔表达式。 P 和 Q 下方的行显示了它们值的所有可能组合。第三列显示了表达式 P || Q 的对应值。
2.1.11.1. 示例(复合条件)¶
请记住,这些表达式可能为真也可能为假。该语句:
boolean x = false;
明确地将布尔变量 x 设置为 false。它类似于英文语句“变量 x 为 false"。它是一个事实陈述。
if 语句更像是一个问题:
martha.seesNet(AHEAD)
这个表达式更像是一个问题。“杰鲁是否看到前方有网?”它可以回答是或否,但它并不是以同样的方式陈述一个事实。
布尔表达式(Java 风格) |
英文翻译(如果为真) |
|---|---|
|
鲍勃前方没有网 |
|
鲍勃至少有一朵花,且鲍勃左侧紧邻的单元格中没有任何东西。 |
|
鲍勃前方或右侧有水,或者两者都有 |
|
鲍勃面向西方且前方没有网 |
2.1.11.2. 自测¶
2.1.12. 语法练习 3d:复合条件¶
2.1.13. 重复执行动作¶
在前几节中,我们学习了如何使用 if-then-else 或 if-then 结构来决定执行哪个动作。在本节中,我们将学习如何创建一块可以连续执行多次的语句块。我们使用重复结构(也称为循环)来实现这一点,它是大多数命令式和面向对象编程语言支持的基本控制结构之一。
重复结构 (或 循环)允许一组语句连续执行多次。有三种重要的重复结构:一种循环对对象集合中的每个对象重复执行某个动作,一种由程序中对象的状态控制的循环,以及一种由计数器(通常是一个数字)控制的循环。在本章中,我们将只关注其中一种循环,即由程序中对象的状态控制的循环。这恰好是许多编程语言中最通用、最基本的重复结构。
2.1.14. 通用重复结构¶
每个重复结构都有两个主要部分:循环体和终止条件。这两个部分提供了一种对循环进行分类的方法。
可重复执行的语句块称为循环 体。每次执行循环体中的语句称为一次循环 趟 (或 迭代),而循环体被执行的次数称为 趟数。
控制条件 是一个用于判断是执行一趟循环体还是终止循环的条件。每执行一趟循环体后,都会重新检查该控制条件。
对循环进行分类的一个标准是基于在第一次遍历循环体之前还是之后检查控制条件。在 前测循环 中,控制条件总是在首次执行循环体之前进行检查。在 后测循环 中,控制条件要等到第一次遍历循环体之后才进行检查。无论哪种情况,每次遍历循环体后都会检查条件,以确定是否需要进行下一次遍历。
对循环进行分类的第二个标准是基于条件为真还是为假会导致执行一趟循环体。在 while 循环 中,条件为真会导致执行一趟循环体,而条件为假则终止循环。在 until 循环 中,条件为真会终止循环,而条件为假则导致执行一趟循环体。while 循环与 until 循环的区别总结如下表所示:
结合这两个标准,我们可以定义四种广泛的循环类别:前测 while、前测 until、后测 while 和后测 until。很少有编程语言同时提供这四种(大多数只提供两种,甚至一种!),但几乎每种命令式和面向对象编程语言都支持的最常见形式是前测 while 循环。在本章的其余部分,我们将 exclusively 专注于 前测 while 循环。
由于前测 while 循环是命令式和面向对象语言中最常见的重复结构,我们将对其进行更深入的探讨。
上图展示了一个通用的前测 while 循环,并使用箭头指示语句执行和条件检查的顺序。
2.1.15. Java 中 while 循环的语法¶
上图展示了 Java 中前置测试 while 循环的 Java 语法。关于该语法,有三点需要特别注意。
条件 必须 放在括号中。
包含条件的括号之后或关键字
else之后 没有分号。while 结构不是方法,这意味着我们不会将其作为消息发送给 Jeroo 对象。
关于编码风格,有三点需要特别注意。
花括号用于定义 while 语句体的开始和结束。务必包含它们。
花括号与单词
while的起始位置对齐。花括号之间的语句应缩进(我们使用 4 个空格)。
2.1.15.1. 示例(前置测试 while 结构)¶
假设名为 Kim 的 Jeroo 没有站在花朵上,但前方有一排花朵。让 Kim 采摘所有这些花朵,并在正前方没有花朵时立即停止。采摘完所有花朵后,Kim 应向左转。
while (kim.seesFlower(AHEAD))
{
kim.hop();
kim.pick();
}
kim.turn(LEFT);
