你真的懂for循环吗?

for循环

顺序选择循环为程序中的三种基本结构,循环可以简单的理解为:重复性地执行特定语句,直到控制条件不满足,也就是直到起控制作用的布尔表达式(Booleanexpression)返回"false"。而whiledo-whilefor分别为Java中三种循环形式之一,但for循环应该是最常使用的循环形式,也是本文的主角。

在这里插入图片描述

基本语法

for循环的格式如下:

for(initialization; Boolean-expression; step)
	statement

其中初始化(initialization)表达式布尔表达式(Boolean-expression)以及步进(step)运算都可以为空,但需注意的是,若布尔表达式为空,则本循环为死循环(无限循环)

代码示例:

for (;;)
	System.out.println("这是一个死循环...");

等同于:

for (; true ;)
	System.out.println("这也是一个死循环...");

执行流程

步骤如下
1.在进行第一次循环之前,首先要写初始化表达式进行变量的初始化。
2.测试布尔表达式:若得到的结果为"false",则循环结束,执行for语句后面的代码行
3.若得到的结果为"true",执行循环体语句。
4.进行步进运算,回到2步骤。

下图是执行流程图:
for循环执行流程图

作用范围

for循环作用范围

1.若for循环后没有{ },则for循环的作用范围到下一个语句的分号截止。
如:

/**
 * @author guqueyue
 * @Date 2020/2/26
 * for循环后不跟{}
 **/
public class ForRange1 {
    public static void main(String[] args) {
        for (int i = 0; i < 3; i++)
            System.out.println("写篇博客不容易...");
        // for循环范围到此截止
        System.out.println("求关注、评论和点赞!");
    }
}

输出结果如下:
在这里插入图片描述
2.若for循环后有{ },则for循环的作用范围到右括号截止。
如:

/**
 * @author guqueyue
 * @Date 2020/2/26
 * for循环后跟{}
 **/
public class ForRange2 {
    public static void main(String[] args) {
        for (int i = 0; i < 3; i++) {
            System.out.println("写篇博客不容易...");
            System.out.println("求关注、评论和点赞!");
        }
        System.out.println("for循环范围到此结束");
    }
}

效果图如下:
在这里插入图片描述

变量作用范围

初始化(initialization)表达式定义的变量的作用范围其实就是for循环的作用范围

循环次数

for循环次数由初始化表达式布尔表达式以及步进运算来控制,如初始化变量为n,布尔表达式为小于等于m,步进为p,则循环次数为:(m-n+1)/p;若是布尔表达式没有等于则不需要+1,次数为:(m-n)/p

for(int i = n; i <= m || i < m+1; i+=p);

同理,步进运算递减的话也差不多,循环次数为(n-m+1)/p;若是若是布尔表达式没有等于则不需要+1,次数为:(n-m)/p

for(int i = n; i >=m || i > m-1; i-=p);

双重for循环

双重for循环其实就是for循环中再嵌套一层for循环,也就是内层for循环作为外层for循环的循环体。当然你也可以嵌套多层循环,但一般为两层,如果你写出了三层及以上的嵌套for循环,往往意味着你把问题复杂化了。

特点:外层循环执行一次,内层循环执行一遍。

代码示例:

/**
 * @author guqueyue
 * @Date 2020/2/25
 * 双重for循环
 **/
public class ForFor {
    public static void main(String[] args) {
        for (int i = 1; i <= 3; i++){
            System.out.print(i + " ");
            for (int j = 3; j <= 6; j++){
                System.out.print("* ");
            }
            System.out.println();
        }
    }
}

如下图:我们不难看出外层循环控制行,内层循环控制列,也就是说外层循环控制有多少行数,内层循环控制有多少列数(为了显示效果,我们把行号打印出来)。
在这里插入图片描述

当然在本文最后一个章节《从心所欲》中,会有双重for循环的扩展使用

天下武功,不拘于形

移形换影

在之前《基本语法》中说过,初始化(initialization)表达式步进(step)运算都可以为空,当然他们也可以待在程序的其他位置。

如:

/**
 * @author guqueyue
 * @Date 2020/3/2
 **/
public class ForChange3 {
    public static void main(String[] args) {
        int i = 0;
        for (; i < 6; ) {
            System.out.println("聪明人才能看到这里..." + i);
            i += 2;
        }
    }
}

控制台打印结果:
在这里插入图片描述

逗号操作符

逗号操作符(仅限于for循环使用)不同于用来分隔函数的不同参数的逗号分隔符,它用于for循环控制表达式的初始化和步进控制部分。你可以在其中使用一系列由逗号分隔的语句,而且那些语句均会独立执行。但需特别注意的是:你可以通过逗号操作符在for循环内定义多个变量,但是它们必须具有相同的类型!

代码示例:

/**
 * @author guqueyue
 * @Date 2020/3/2
 * 逗号操作符
 **/
public class CommaOperator {
    public static void main(String[] args) {
        for(int i = 1, j = i + 10; i < 5; i++, j = i * 2) {
            System.out.println("i = " + i + " j = " + j);
        }
    }
}

Output:
在这里插入图片描述

中断五式

有五种方式可以中断for循环,分别为: System.exit()、return、break、continue以及标签。

第一式:玉石俱焚

System.exit(int status),终止当前正在运行的Java虚拟机。参数用作状态码;根据惯例,非 0 的状态码表示异常终止。

第二式:浪子回头

return,不同于System.exit(0)的直接终止Java虚拟机,return只会导致当前方法退出,并使当前方法返回return后的值;如果在返回void的方法中没有return语句,那么在该方法的结尾处会有一个隐式的return。

如:

/**
 * @author guqueyue
 * @Date 2020/3/2
 * return
 **/
public class ForInterrupt2 {
    public static void main(String[] args) {
        interrupt(5);
        for (int i = 0; i < 2; i++) {
            System.out.println("i = " + i);
        }
    }

    private static void interrupt(int num) {
        for (int n = 0; n < num; n++) {
            System.out.println("n = " + n);
            return;
        }
        System.out.println("我不会执行了!");
    }
}

Output:
在这里插入图片描述

第三式:一往无前

break,不同于retunr会退出当前整个方法,break用于强行退出循环,不执行循环中剩余的语句。也就是说,break只会退出当前的循环,若循环后还有语句,将会继续执行。

如:

/**
 * @author guqueyue
 * @Date 2020/3/2
 * return
 **/
public class ForInterrupt3 {
    public static void main(String[] args) {
        interrupt(5);
        for (int i = 0; i < 2; i++) {
            System.out.println("i = " + i);
        }
    }

    private static void interrupt(int num) {
        for (int n = 0; n < num; n++) {
            System.out.println("n = " + n);
            break;
        }
        System.out.println("该执行的还是会执行的!");
    }
}

Output:
在这里插入图片描述

第四式:以退为进

continue,它不同于break,它只停止执行当前的迭代,然后退出循环起始处,开始下一次迭代

代码示例如下:

/**
 * @author guqueyue
 * @Date 2020/3/2
 * break和continue在for循环中的运用
 **/
public class BreakAndContinue {
    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            if(i == 74) break; // 如果i等于74,退出当前循环
            // 如果i不是9的倍数,直接中止当前迭代,开启下次迭代
            // 也就是说如果i是9的倍数,则继续本次迭代,再开启下次迭代
            if(i % 9 != 0) continue;
            System.out.print(i + " ");
        }
    }
}

Output:
在这里插入图片描述

最后一式:从心所欲

标签,它一般在我们之前提到的双重for循环中配合break或者continue关键字使用。

面试题警告

在介绍标签之前,我们先来看道面试题吧!

请听题:请选择以下程序的运行结果:

public Class Test {
	public static void main(String[] args) {
		http://www.baidu.com
		for(int i = 0; i < 0; i++) {
			System.out.print(i);	
		}
	}
}

A . 打印0
B. 什么都不打印
C. 编译报错
D. 运行报错

可能很多朋友可能跟我之前一样,第一眼就看到这个百度的网址是个啥玩意,果断选 C. 编译报错呀,这想都不用想。但是想象是美好的,现实却往往是残酷的,答案选 B. 什么都不打印 ,因为http:是个标签,而//是注释,www.baidu.com是被注释的内容!所以这段程序运行能通过!!

正如这个http:,标签是后面跟有冒号的标识符,一般为:

label1: // 其中label1为自定义的名称

友情提示标签之后最好紧跟循环语句,也就是说最好不要在标签和循环语句之间置入任何语句;如果你没有这样做,编译器不一定会报错,但你很可能无法达成想要的效果!!!

以下是break和continue关键词以及它们结合标签在双重for循环中的运用:

label1:
outer-iteration {
	inner-iteration {
		//...
		break; // (1)中断内部迭代,回到外部迭代
		//...
		continue; // (2)跳过内部循环的本次迭代,直接开启内部循环的下次迭代
		//...
		continue label1; // (3)同时中断内部迭代和外部迭代,回到标签处
						 // 随后继续迭代过程,但却是从外部迭代开始
		//...
		break label1; // (4)此处也会中断所有迭代,回到标签处,但并不重新进入迭代;
					  //  也就是说,此处它完全中止了两个迭代
	}
}

以上解释可能会有些抽象。没关系,接下来我们具象化一点,用具体实例来解释:

(1) break在双重for循环中的运用实例:

for (int i = 1; i <= 3; i++){
	System.out.print(i + " ");
	for (int j = 3; j <= 6; j++){
		System.out.print("*" + j + " ");
 		break; // 当然你也可以在break前加入if判断
	}
	System.out.println();
}

控制台输出结果如下,内部迭代仅输出一次就被break中断,回到外层for循环:
在这里插入图片描述
(2) continue在双重for循环中的运用实例:

for (int i = 1; i <= 3; i++){
	System.out.print(i + " ");
	for (int j = 3; j <= 6; j++){
		if(j == 3) continue; // 如果j等于3,则跳过本次内部循环
		System.out.print("*" + j + " ");
	}
	System.out.println();
}

控制台输出结果如下,j等于3时的内部迭代直接被跳过:
在这里插入图片描述
(3) break + 标签在双重for循环中的运用实例:

outer:
for (int i = 1; i <= 3; i++){
	System.out.print(i + " ");
	inner:
	for (int j = 3; j <= 6; j++){
		System.out.print("*" + j + " ");
		break outer;
	}
System.out.println();
}

如图,迭代执行一次便被完全中止:
在这里插入图片描述
注:若break outer改为break inner,其实等同于break

(4) continue + 标签在双重for循环中的运用实例:

outer:
for (int i = 1; i <= 3; i++){
	System.out.print(i + " ");
    inner:
    for (int j = 3; j <= 6; j++){
		System.out.print("*" + j + " ");
		continue outer;
	}
	System.out.println();
}

如图:内部循环只执行一次便被中止,回到标签所在的外部循环,重新开始迭代过程
在这里插入图片描述
注:同理,若continue outer改为continue inner,其实等同于continue

参考资料:Bruce Eckel. Thinking in Java Fourth Edition.

非常好,我们来**一步一步、彻底讲清楚 C 语言中这个用于质因数分解的 `for` 循环**: ```c for (i = 2; i <= n; i++) { while (n % i == 0) { printf("%d*", i); n = n / i; } } ``` --- ### 🔍 我们的目标是什么? 我们要把一个正整数 $ n $ 分解成若干个**质数(素数)相乘**的形式。 比如: - $ 150 = 2 \times 3 \times 5 \times 5 $ - 所以输出应该是:`n=2*3*5*5*` --- ### 🧩 这个 for 循环是怎么工作的? #### 第一步:整体结构 ```c for (i = 2; i <= n; i++) // 从 i=2 开始,一直到 i<=n { while (n % i == 0) // 如果当前 n 能被 i 整除 { printf("%d*", i); // 输出这个 i(就是一个因子) n = n / i; // 把 n 除以 i,继续看还能不能再除 } } ``` 我们用 **$ n = 150 $** 来手动模拟一遍执行过程: --- ### ✅ 模拟执行:$ n = 150 $ | 步骤 | i 的值 | 条件 `i <= n`? | `n % i == 0`? | 操作 | 新的 n | |------|-------|----------------|---------------|------|--------| | 1 | 2 | 是 (2 ≤ 150) | 150%2 == 0 ✔️ | 输出 2*, n = 150/2 = 75 | 75 | | 2 | 仍然在 i=2 | 是 (2 ≤ 75) | 75%2 ≠ 0 ❌ | 不进 while,i++ → i=3 | 75 | | 3 | 3 | 是 | 75%3 == 0 ✔️ | 输出 3*, n = 75/3 = 25 | 25 | | 4 | 仍然在 i=3 | 是 | 25%3 ≠ 0 ❌ | 不进 while,i++ → i=4 | 25 | | 5 | 4 | 是 | 25%4 ≠ 0 ❌ | 不进 while,i++ → i=5 | 25 | | 6 | 5 | 是 | 25%5 == 0 ✔️ | 输出 5*, n = 25/5 = 5 | 5 | | 7 | 仍然在 i=5 | 是 (5 ≤ 5) | 5%5 == 0 ✔️ | 输出 5*, n = 5/5 = 1 | 1 | | 8 | i++ → i=6 | 6 ≤ 1? ❌ | 结束循环 | — | — | 最终输出:`2*3*5*5*` ✔️ 完全正确! --- ### 💡 关键理解点 #### 1. **为什么 `while` 而不是 `if`?** 因为同一个质因子可能出现多次! 例如:$ 8 = 2 \times 2 \times 2 $ 如果我们只用 `if`,只能除一次,剩下 4,得不到完整分解。 而 `while` 会一直除下去,直到不能再除为止。 ✅ 所以 `while` 是为了处理**重复因子**。 --- #### 2. **i 一定是质数吗?会不会把合数也当成因子输出?** 比如:i=4 时,n 还会被 4 整除吗? 不会!因为在 i=2 的时候,已经把所有的 2 都除干净了。 所以当 i=4 时,n 已经是奇数了,不可能再被 4 整除。 🎯 这就是这个算法的巧妙之处: > 即使 i 是合数(如 4, 6, 8...),但由于更小的质因子已经被完全去除,n 不可能再被它们整除。 所以实际上,**只有质数才能进入 `while` 循环并输出**。 --- #### 3. **n 在不断变小,i 却从 2 一路增加到原来的 n,会不会浪费?** 是的,有一定冗余,但我们可以通过优化提前结束: ```c for (i = 2; i * i <= n; i++) ``` 当 $ i^2 > n $ 时,如果 $ n > 1 $,那剩下的 $ n $ 本身就是质数。 但这道题没做这个优化,也没问题。 --- ### ✅ 举个简单例子帮助记忆 假设 $ n = 12 $ | i | n % i == 0? | 操作 | |---|-------------|------| | 2 | 12%2=0 → 是 | 输出 2*, n=6 → 再试 2 | | | 6%2=0 → 是 | 输出 2*, n=3 → 再试 2 | | | 3%2≠0 → 否 | i++ → i=3 | | 3 | 3%3=0 → 是 | 输出 3*, n=1 | | i=4,5,... | i>n → 结束 | 输出:`2*2*3*` → 正确! --- ### 📌 总结一句话: > 这个 `for` 循环从 2 开始逐个尝试每个数是不是 $ n $ 的因子,用 `while` 不断除去同一个因子,直到除尽为止。虽然 i 遍历所有整数,但实际上只有质数会被输出。 --- ### 知识点(列出该代码中遇到的知识点) - **试除法分解质因数**:从最小整数开始逐个试除,直到商为1。 - **while循环处理重复因子**:确保每个质因子被完全除去,适用于幂次大于1的情况。 - **for循环与变量动态变化**:循环中`n`不断减小,影响循环结束条件,需理解运行时行为。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值