建议阅读:第5.1-5.9节

循环简介

在第3章中,我们看到if-else构造使我们的程序具备做出决策的能力。在第5章中,我们将看到允许我们在程序中构建重复的各种结构。

while循环

Java中的基本重复结构是while循环。其基本结构如下。

While (<test>){<要重复的语句>}

当程序执行第一次到达while语句时,测试被求值。如果测试结果为true,则执行进入循环体,执行花括号内的语句。执行完主体语句后,我们再次返回到测试。如果测试结果再次为true,我们将再次通过主体。这个过程不断重复,直到最终测试结果为false。此时,继续执行body之后的下一条语句。

在编写while循环时,必须注意确保语句体中的语句允许您最终达到循环测试结果为false的状态。否则,您的程序将永远卡在循环中。(这种情况被称为无限循环。)

一个基本的例子:验证

while循环的一个直接赢博体育是实现对输入的验证检查。下面是基于第一个编程作业的示例。由于风寒公式仅适用于特定范围内的温度和风速大于2英里/小时,因此我们必须检查用户输入的温度和风速。

下面的示例代码展示了如何使用while循环不断要求用户输入,直到用户输入有效的输入。

包风寒指数;进口java.util.Scanner;公共类WindChill{公共静态void main(String[] args){扫描器输入=新的扫描器(System.in);双t v, wct);system . out。print(“输入华氏温度:”);t = input.nextDouble();while(t < -58 || t > 41) {System.out。println(“温度必须在-58华氏度到41华氏度的范围内”);system . out。print(“输入华氏温度:”);t = input.nextDouble();} system . out。打印(“输入风速,单位为mph:”);v = input.nextDouble();while(v < 2) {System.out;println(“风速必须大于2英里/小时”);system . out。打印(“输入风速,单位为mph:”);v = input.nextDouble();} wct = 35.74 + 0.6215*t -35.75*数学。战俘(v, 0.16) + 0.4275 * t * Math.pow (v, 0.16);system . out。println(“风寒温度是”+ wct);}}

循环计数器变量

循环最常见的赢博体育之一是使用称为循环计数器的整数变量来控制循环的行为。下面是一个典型的例子——在这个例子中,循环计数器只是确保循环重复所需的次数。

public static void main(String[] args) {int n = 0;while(n < 10) {System.out.println("Hello!");N = N + 1;}}

示例中的变量n充当循环计数器。在进入循环之前,我们给n一个初始值0。循环测试监视当前n的值,当n达到10时停止重复。最后,循环中的最后一条语句确保n的值在每次循环中增加1。这保证了循环最终将终止。

该声明

N = N + 1;

通常称为增量语句。它导致存储在n中的值在每次求值语句时增加1。这是一种非常常见的语句类型,Java提供了一种方便的快捷形式:

n + +;

这是一样的。

通常,counter变量也不仅仅用于计算我们进行了多少次重复。通常,我们试图在每次循环迭代中计算的东西在某种程度上取决于循环计数器的当前值。下面是一个示例来说明这一点:下面代码的目标是打印一个2n的值表,因为n的范围是从0到14。

public static void main(String[] args) {int n,power;N = 0;当(n < 15) {power = (int)数学。战俘(2 n);system . out。Println(“2的幂” + n + " = “ +幂”);n + +;}}

注意,输出的是2n,这当然取决于当前n的值。

打印表格

下面是另一个使用循环打印值表的示例。这个版本的风速程序让用户输入一个温度,然后使用一个循环以2英里/小时的步骤打印风速范围从2英里/小时到20英里/小时的风寒温度表。

包风寒指数;进口java.util.Scanner;public class Table {public static void main(String[] args){扫描器输入=新扫描器(System.in);双t v, wct);system . out。print(“输入华氏温度:”);t = input.nextDouble();while(t < -58 || t > 41) {System.out。println(“温度必须在-58华氏度到41华氏度的范围内”);system . out。print(“输入华氏温度:”);t = input.nextDouble();} //打印风速和风寒表。println(“风速、风寒”);V = 2.0;而(v <= 20.0) {wct = 35.74 + 0.6215*t-35.75*数学。战俘(v, 0.16) + 0.4275 * t * Math.pow (v, 0.16);system . out。Println (v + " " + wct);V = V + 2.0;}}

这种方法是有效的,但是会生成格式不佳的表。例如,在输入10f上,该程序打印一个表,如下所示

风速风寒2.0 6.788387329176881 4.0 2.663795973321772 6.0 0.03030239145645819 8.0 -1.9445568983790018 10.0 - 3.540216784228060603 12.0 -4.886925405592865 14.0 -6.05660500717706 16.0 -7.09341028962846 18.0 -8.026506209329085 20.0 -8.876220556825402

得到一个好看的表的关键是在print语句中进行更多的控制。我们可以通过使用System.out.printf()代替System.out.println()来做到这一点。Printf表示“格式化打印”。要使用这个命令,我们需要使用格式字符串和要打印的变量列表的组合。格式字符串是要打印的文本块,包含格式说明符。格式说明符充当我们想要打印的值的占位符。对于想要打印的每个变量,都需要一个格式说明符。

典型的格式说明符是这样的

% 8.2度

该说明符表示要打印一个浮点数,以便该数字在打印输出中总共占用8列,小数点后有2位数字。如果您要打印的数字需要少于8个字符,则输出将在左侧填充额外的空格,以使整个数字恰好占用8个字符。

下面是print语句的改进版本,用于打印风速表的循环:

System.out.printf(8.2“% % 8.2 f \ n”,v, wct);

有了这个改变,程序打印了一个更漂亮的10华氏度的风寒表。

风速风寒2.00 6.79 4.00 2.66 6.00 0.03 8.00 -1.94 10.00 -3.54 12.00 -4.89 14.00 -6.06 16.00 -7.09 18.00 -8.03 20.00 -8.88

您可以在教材的第4.6节中阅读有关printf()命令和格式说明符的更多信息。

使用循环进行搜索

循环的一个常见赢博体育是在一系列值中进行系统搜索,寻找满足某些特殊条件的值。赢博体育程序的一个有用的例子是寻找整数的除数的问题。为了测试一个整数d是否能被另一个整数n整除,我们可以使用下面的逻辑:

如果(n%d == 0) {// d除以n}

我们可以将这个测试与循环结合使用,找到赢博体育能被整数n平均整除的整数:

system . out。print(“输入n的值”);int n = input.nextInt();Int d = n - 1;while(d > 1) {if(n % d == 0) System.out.println(d);d——;}

一个密切相关的赢博体育是确定一个数字是否是素数的问题。确定这一点的一种方法是使用上面的逻辑并记录我们找到的除数:

system . out。print(“输入n的值”);int n = input.nextInt();Int d = n - 1;int divisorCount = 0;while(n % d == 0) {if(n % d == 0)d——;} if(divisorCount == 0) System.out。println(“数字” + n + “是素数”);system . out。println(“数字” + n + “不是素数”);

赢博体育——把东西加起来

while循环很有用的一个常见赢博体育是对数字列表进行相加。如果要添加的数字遵循简单且可预测的模式,则编写将数字相加所需的逻辑相对容易。

这里有一个简单的例子。假设我们要计算和

对于某个整数n,下面的代码进行计算。

public static void main(String[] args){扫描器输入=新扫描器(System.in);system . out。println(“为N输入一个值”);int N = input.nextInt();Double sum = 0.0;Int n = 1;双项;while (n <= n) {term = 1.0/n;Sum = Sum + term;n + +;} system . out。println("The sum is " + sum);}

除了常用的循环计数器变量n(用于计算加到总和中的项数)之外,我们还使用了第二个变量sum(用于存储运行总数)。在循环的每次迭代中,我们计算下一个要添加到总和中的项,将其添加到运行总数中,然后对计数器进行自增。如果循环计数器和我们试图生成的项之间的关系很简单,那么这个策略就很容易实现。

在下一个示例中,循环计数器与我们要添加到运行总数中的项之间的关系变得更加复杂。在这个例子中,我们要计算和

N != n * (n -1) * (n -2) *⋯* 2 * 1

是N的阶乘,上过数学150的人可能知道,当N变得很大时,这个和的极限是e = 2.71828182846…

很容易看出,如果这个总和的循环计数器从n = 1到n = n,当计数器为n时,我们需要添加到运行总数的项是1/n!问题是我们没有简单的方法来计算n!

解决这个困难的方法是重用我们之前对幂使用的策略。如果我们刚刚算完1/n!我们把结果存储在一个名为term的变量中,我们可以很容易地计算1/(n+1)!通过计算term/(n+1)

下面的代码实现了这些思想来正确地计算总和。

public static void main(String[] args) {int n, n;二重项,和;system . out。print(“输入字数:”);扫描器输入=新的扫描器(System.in);N = input.nextInt();N = 1;Sum = 1.0;Term = 1.0;while (n <= n) {sum = sum + term;//计算下一项n++;Term = Term / n;} system . out。println("Sum = " + Sum);system . out。println("e = " + Math.E);}

请注意,这里的逻辑有些敏感,很难正确理解。特别是,增加n的语句和计算新项的语句的相对顺序在这里非常重要。

判断你的逻辑是否正确的一个相当有效的方法是“玩电脑”,用手追踪逻辑。如果你这样做,你会看到和的第一项是1,第二项是1/2,第三项是1/6,就像它应该的那样。

跳出循环

有时,当我们找到我们要找的东西时,搜索可以提前结束。在最后一个例子中,一旦我们找到一个有效的除数,继续搜索除数没有多大意义。对于这种情况,可以使用break语句提前退出循环。

system . out。print(“输入n的值”);int n = input.nextInt();Int d = n - 1;While (n % d == 0) {if(n % d == 0) break;d——;} if(d == 1) System.out。println(“数字” + n + “是素数”);system . out。println(“数字” + n + “不是素数”);

在循环中的任何地方键入break语句将导致我们立即退出循环。这在这种情况下是合适的,因为我们希望在找到有效的除数后立即退出循环。

这里的逻辑利用了这样一个事实,即如果n不是素数,我们将遇到一个有效的除数,并在d有机会下降到1之前跳出循环。

延伸的循环

while循环必须遵守的一个约束是,我们必须能够在进入循环之前对测试进行评估。这有时是一个问题,因为当我们第一次遇到测试时,我们可能没有足够的信息来正确评估测试。为了解决这个问题,Java还提供了另一种循环结构,do-while循环。下面是do-while循环的基本结构:

do{//语句重复}while(<test>);

与while循环一样,do-while循环在其循环体中重复语句,直到<test>为假。do-while循环的不同之处在于,在执行测试之前,我们有机会遍历循环体。这很有用,因为在某些赢博体育程序中,<test>在我们有机会为我们做body语句所做的事情之前是没有意义的。

do-while循环通常用于验证输入。下面是风速计算的例子,这一次使用了一种稍微不同的方法来验证输入:

包风寒指数;进口java.util.Scanner;公共类WindChill{公共静态void main(String[] args){扫描器输入=新的扫描器(System.in);双t v, wct);do {System.out。print(“输入温度在-58到41之间”);t = input.nextDouble();} while(t < -58 || t > 41);do {System.out。打印(“输入风速> 2英里每小时:”);v = input.nextDouble();} while(v < 2);wct = 35.74 + 0.6215*t-35.75*数学。战俘(v, 0.16) + 0.4275 * t * Math.pow (v, 0.16);system . out。println(“风寒温度是”+ wct);}}

for循环

while循环和循环计数器变量的组合是程序中非常常见的配置:

Int n = 0;while(n < 100){//用n++做一些事情;}

这种代码模式经常出现在赢博体育程序中,以至于赢博体育C家族语言都提供了一种方便的替代方法,称为for循环:

For (int n = 0;N < 100;n++){//重复的语句}

for循环的基本结构是

For (<initial >;<test>;<increment>) {<body>}

这和结构完全等价

<initial > while(<test>) {<body> <increment>}

并简单地提供了一种更紧凑的方式来构建循环。

下面是用for循环代替while循环重新实现的wind chill table打印代码:

system . out。println(“风速、风寒”);对于(v = 2.0;V <= 20.0;v = v + 2.0) {wct = 35.74 + 0.6215*t-35.75*数学。战俘(v, 0.16) + 0.4275 * t * Math.pow (v, 0.16);System.out.printf(8.2“% % 8.2 f \ n”,v, wct);}

嵌套循环

在某些情况下,我们会发现有必要将循环放在另一个循环中。当我们必须执行一些需要循环的重复任务时,这种情况自然会发生。

下面是原文中的一个例子。这个程序打印一个乘法表:

public class MultiplicationTable {/** Main方法*/ public static void Main (String[] args){//显示表标题System.out。println(“乘法表”);//显示数字title System.out。打印(" ");For (int j = 1;J <= 9;j + +) system . out。Print (" " + j);System.out.println(“\ n -----------------------------------------");//打印表体for (int i = 1;I <= 9;i++) {System.out。Print (i + " | ");For (int j = 1;J <= 9;j++){//显示产品并正确对齐。Printf(“%4d”,I * j);} System.out.println ();}}

由于乘法表的每一行都有多个条目,因此我们需要一个循环来打印每一行。该循环本身将位于另一个循环中,该循环沿着表的行进行工作。

下面是另一个涉及嵌套循环的例子。我们在上面看到了如何编写一些逻辑来确定整数n是否是素数。我们可以很容易地将其转换为扫描整数范围查找素数的代码。下面的逻辑检查2到1000之间的赢博体育奇数,并打印它找到的赢博体育素数。

Int n = 3;当(n < 1000) {int d = n - 1;While (n % d == 0) {if(n % d == 0) break;d——;} if(d == 1) System.out.println(n);N = N + 2;}