目录
循环用于在重复执行某些操作代码的时候进行使用,减少代码的编写难度,避免代码的重复编写,增强代码的重用性。结合计数器控制循环次数,完成代码的有限或者无限次的执行。
一、for循环
1、语法结构
for(初始化表达式;布尔表达式;更新表达式){
循环体;(通过写java语句完成一定的操作)
……
}
布尔表达式:值只能是true或者false,不可以是其他类型的值,用于判断条件
2、执行原理
当for循环开始执行后,先运行初始化表达式,对所需的计数器变量进行一个初始化操作,然后看计数器变量的值是否满足布尔表达式的要求,如果满足则执行循环体中的java语句,否则执行更新表达式,对计数器变量的值进行更新,再看是否满足关系表达式的要求,满足则执行循环体,不满足则更新表达式
由这个过程我们可以看出,在整个for循环的执行过程中,初始化表达式只执行一次。整个过程相当于一个圆环,如果布尔表达式的值为假,则整个圆环砍断。
3、for循环的特性
虽然for循环中语法结构是固定的,但是三个表达式并不是必须的,表达式可以省略但是注意分号是不能省略的。例如:我们可以写成 for(a;b;c),还可以写成 for(a;b; )、for(a; ;)、for( ; ; )等形式;
例如:计算1-10的和;
代码如下所示:
//第一种
int sum=0;
for(int i=1;i<=10;i++){
sum+=i;
System.out.println(sum);
}
//第二种
int i=1; //计数器变量在外边以局部变量的形式初始化
int sum=0;
for (;i<=10;i++){
sum+=i;
System.out.println(sum);
}
//第三种(结合后边循环的中断)
int i=1; //充当了初始化表达式
int sum=0; //充当了初始化表达式
for(;;i++){
if (i<=10) sum+=i; //i<=10执行循环体,充当了布尔表达式
else break; //i>10退出循环,充当了布尔表达式
System.out.println(sum);
}
//第四种(结合后边循环的中断)
int i=1; //充当了初始化表达式
int sum=0;
for (;;){
if (i<=10)sum+=i; //i<=10执行循环体,充当了布尔表达式
else break; //i>10退出循环,充当了布尔表达式
i++; //充当了更新表达式
System.out.println(sum);
}
以上均是可以正常执行的,仔细观察可以看出在for后省略的表达式都以其他方式给出,对于循环结构一定要有一个出口,这个出口一般是布尔表达式和更新表达式(或者具有代替作用的java语句)共同构成的。
如果真的完全省略了布尔表达式或者更新表达式,很可能会构成死循环,循环就无法结束了。
如下例代码:
int i=1;
int sum=0;
for (;;){
if (i<=10)sum+=i; //循环没有退出的出口
i++;
System.out.println(sum);
}
和下例代码:
int i=1;
int sum=0;
for (;;){
if (i<=10)sum+=i; //没有循环的计数变量更新表达式
else break;
System.out.println(sum);
}
这两种写法除非人为的中断,否则会无休止的执行下去。这就是我们所说的死循环。在代码编写的过程中,我们要避免构成死循环。
二、嵌套
所有的控制语句都是可以互相进行嵌套使用的,主要有以下两种:
1、和if的嵌套
例如:接收用户键盘输入的一个数,判断该数是不是奇数
Scanner in=new Scanner(System.in);
int n=in.nextInt();
if (n%2!=0) System.out.println("是奇数");
else System.out.println("是偶数");
输出1-100中奇数的和:运算符’+=‘用于完成累加的操作,累加到变量sum里,用以求和;
int sum=0;
for(int i=1;i<=100;i++) {
if (i % 2 != 0) {
sum+=i;
}
}
System.out.println(sum);
2500
进程已结束,退出代码为 0
2、和for循环的嵌套(难点)
(1)使用方法:
for(初始化表达式;布尔表达式;更新表达式){
for (初始化表达式;布尔表达式;更新表达式){
//循环体语句
}
}
注意:其实在嵌套的时候,将内部被嵌套的一个循环看作一个整体就好了,不要将其特殊化,虽然内部是一个循环,但是它本身只相当于一段循环体,相当于一段符合java语法规则的代码段而已。
(2)注意事项
注意变量的重名问题,局部变量之间如果作用域不存在重叠,则可以重名,否则不可以。
但是局部变量和成员变量之间可以重名,只不过在二者的作用域重叠区域,局部变量会覆盖掉成员变量的作用。
例如:
for(int i=0;i<10;i++){
for (int i=0;i<10;i++){
System.out.println(i);
}
}
会报错:【java: 已在方法 main(java.lang.String[])中定义了变量 i】,因为两个局部变量i之间存在作用域的重叠
例如:
(3)举例(9*9)乘法表
1*1=1
2*1=2 2*2=4
3*1=3 3*2=6 3*3=9
4*1=4 4*2=8 4*3=12 4*4=16
5*1=5 5*2=10 5*3=15 5*4=20 5*5=25
6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36
7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49
8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64
9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81
分析该表:
首先乘号左边的数,和当前的行数相同。 乘号右边的数,和当前的列数相同;且每一行的列数等于当前行的行数;如果行为 i 变量,那么按照行为单位来观察,每一行的代码如下所示:
int i=1; //行数
for(int j=1;j<=i;j++)
System.out.print(i+"*"+j+"="+(i*j));
那么我们需要一个变量去控制行数变量,且每一列打印完后,都要换行,如下:
for(int i=1;i<=9;i++) {
for (int j = 1; j <= i; j++)
System.out.print(i + "*" + j + "=" + (i * j)+"\t");
System.out.println();
}
//简单来说,就是在不同的i值(行)的情况下
//执行里面的代码块(for循环),共执行九次,这样
//就能够做到九九乘法表的输出
输出如下:
1*1=1
2*1=2 2*2=4
3*1=3 3*2=6 3*3=9
4*1=4 4*2=8 4*3=12 4*4=16
5*1=5 5*2=10 5*3=15 5*4=20 5*5=25
6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36
7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49
8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64
9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81
进程已结束,退出代码为 0
(4)举例:素数的判断
首先了解什么是素数:素数就是这个数只能被1和它本身整除,
判断n是不是素数的方式有三种,第一种是判断2~n-1之间的数能否整除n,如果全都不可以,那么这个数就是素数。第二种是判断2~n/2之间的数能够整除n,因为n的因数必然不可能大于n/2,如果全都不可以,那么这个数就是素数。第三种是判断2~√n,因为n=√n*√n,那么它的因数必然一个小于等于√n,一个大于等于√n,所以,在√n及以内,如果找不到因数,那么这个数就是素数了。
Scanner in=new Scanner(System.in);
int n=in.nextInt();
boolean end=true;
for (int i=2;i<=sqrt(n);i++){
if (n%i==0) {
end=false;
break;
}
}
/*
if (end){
System.out.println("是素数");
}else
{
System.out.println("不是素数");
}
*/
//以上if段可以用三元表达式来代替
System.out.print(end?n+"是素数":n+"不是素数");
示例:
6
6不是素数
进程已结束,退出代码为 0
二、while循环和do-while循环
1、while循环
(1)语法结构
while(布尔表达式){
循环体(JAVA语句);
}
(2)执行原理
当该语句开始执行的时候,会先判断布尔表达式是否为真,如果为真,则执行循环体,否则不执行当前循环。执行完循环体后再次判断布尔表达式的真假,如果为真继续执行循环体,然后再判断,再执行,直到布尔表达式的判断结果为假,循环结束。
(3)循环次数
该循环语句的循环次数为0~N次,是可以构成死循环的。
(4)举例(输出1-10)
int i=1;
while(i<=10){
System.out.print(i+"\t");
i++;
}
1 2 3 4 5 6 7 8 9 10
进程已结束,退出代码为 0
2、DO-while循环
(1)语法结构
do{
循环体Java语句;
}while(布尔表达式);
注意在语句的末尾,和其他的循环语句不同,需要写上分号来作为语句的结束。
(2)执行原理
当执行该语句的时候,会先执行循环体语句,然后再对while后的布尔表达式,如果表达式的结果为真,则再次执行循环体,然后再判断,再执行,直到布尔表达式的值为假,循环停止。
(3)循环次数
该循环语句的循环次数为1~N次,因为会先执行一次语句然后再进行判断。
三、死循环(以while循环为例)
上文中我们每种循环都提到了死循环,但是构成死循环也是有一定的条件的,并且在死循环后的语句会怎么样呢?
如图所示,我们知道如果有死循环,会报错
int i=0;
while(true){
i++;
}
System.out.print(i);
根据错误提示,可以发现在死循环后语句是提示无法执行的。
java: 无法访问的语句
那么布尔表达式在什么情况下会被编译器认定为永真呢?针对三种可能情况进行分析
(1)直接写入boolean值
while(true){ },这种将被编译器直接判断为true,那么它之后的语句就确实不能执行到的,从编译阶段就能发现错误。
(2)字面值的比较
while(5>3) { },这种通过字面值比较构成的布尔表达式,编译器可以直接的判断为true,同样会在编译阶段就报错。
(3)变量的比较
例一:
boolean A=true;
int i=0;
while(A){
i++;
}
System.out.print(i);
如上代码,这种是可以顺利执行的,只不过从控制台输出结果就可以明显的看出来,最后的输出语句并没有执行。
例二:
int i=3;
int j=5;
int k=0;
while(j>i){
k++;
}
System.out.print("happy");
如上代码,这种是可以顺利执行的,只不过从控制台输出结果就可以明显的看出来,最后的输出语句并没有执行。
以上从我们自身的主观印象上,是永真的,但是编译器没有发现,这是因为在编译阶段是不会进行相关运算的,编译器不会判断关系表达式 j > i 的真假,是在运算阶段得出结果的。
四、循环的中断
1、break
(1)break是Java关键字
(2)可以作为单独的一个完整的java语句
(3)可以用在循环和switch语句中,用来中止整个分支和整个循环。
(4)当break用在循环中时,会中断离他最近的一个循环,可以跳出那个循环。这将节省计算机的资源,增强代码的执行效率。
2、continue
(1)continue时Java关键字
(2)可以作为单独的一个完整的java语句
(3)可以用于循环中,用来中止当次循环。
(4)当continue用在循环中时,会跳出离他最近的一个循环,可以跳出当次循环,有助于增强代码的执行效率。
3、两种中断的区别
break是跳过所有的循环,continue是跳过当次循环
例如:
int i;
for (i=1;i<=3;i++){
if (i==2) break;
System.out.println(i+"-"+"♥");
}
System.out.print(i);
1-♥
2
进程已结束,退出代码为 0
在i==2的时候,执行了break语句,这时我们可以看出来,”2-♥“没有进行输出,并且i的值也九次停止了,for循环的语句没有再按照原理继续执行更新表达式,而是彻底的跳出了循环,输出结果为2。
如果换成continue语句:
int i;
for (i=1;i<=3;i++){
if (i==2) continue;
System.out.println(i+"-"+"♥");
}
System.out.print(i);
输出结果则不相同,可以发现在执行了continue之后,”2-♥“没有输出,但是之后的输出依旧进行,i的值依旧在增加,for循环依旧在照常执行,直到不满足i<=3条件之后,该循环才结束。
1-♥
3-♥
4
进程已结束,退出代码为 0
4、嵌套中止
跳出离他最近的一个循环
int i;
for (i=1;i<=3;i++){
for (int j=1;j<=3;j++) {
if (j==2) break;
System.out.println(j + "-" + "♥");
}
System.out.println("第"+i+"轮循环结束");
}
输出结果:可以观察到每轮输出都没有2-♥的输出就结束了,跳出了距离最近的内部循环
1-♥
第1轮循环结束
1-♥
第2轮循环结束
1-♥
第3轮循环结束
进程已结束,退出代码为 0
continue也是同理,跳出最近的循环的当次循环,示例如下:
int i;
for (i=1;i<=3;i++){
for (int j=1;j<=3;j++) {
if (j==2) continue;
System.out.println(j + "-" + "♥");
}
System.out.println("第"+i+"轮循环结束");
}
输出如下:可以观察出每一轮输出虽然跳过了2-♥,但是还是在往后执行的,因为输出了3-♥。
1-♥
3-♥
第1轮循环结束
1-♥
3-♥
第2轮循环结束
1-♥
3-♥
第3轮循环结束
5、新特性
循环是可以起名字的,例如:
int i;
for1:for (i=1;i<=3;i++) {
for2:for (int j = 1; j <= 3; j++) {
if (j == 2) break for1;
System.out.println(j + "-" + "♥");
}
System.out.println("🌙");
}
System.out.println("⭐");
输出如下:可以观察到 j=1 是正常的输出的【1-♥】,但是当J=2时,因为执行了break for1,而for1是外层循环,所以后边的输出🌙没有执行到,并且因为外层循环直接结束了,执行了循环后的语句,输出一颗星星。
1-♥
⭐
进程已结束,退出代码为 0