Saul's blog Saul's blog
首页
后端
分布式
前端
更多
分类
标签
归档
友情链接
关于
GitHub (opens new window)

Saul.J.Wu

立身之本,不在高低。
首页
后端
分布式
前端
更多
分类
标签
归档
友情链接
关于
GitHub (opens new window)
  • Java入门基础

    • 计算机常识

    • Java语言概述

    • 基本语法

      • Java-关键字与保留字
      • Java-标识符(Identifier)
      • Java-变量
      • Java-基本数据类型-整型
      • Java-基本数据类型-浮点型
      • Java-基本数据类型-char字符
      • Java-基本数据类型-boolean布尔类型
      • Java-基本数据类型之间的运算规则
      • 字符串类型 String
      • 进制
      • 运算符
      • Scanner类
      • 流程控制-分支结构
      • 流程控制-循环结构
        • 前言
        • 循环结构
        • 循环语句分类
        • 组成部分
        • for循环
          • 语法格式
          • 执行过程
          • 练习1
          • break关键字
          • 练习2
          • 练习3
          • 练习4
        • while循环
          • 语法格式
          • 执行过程
          • 注意点
          • 和for循环的区别
        • do-while循环
          • 语法格式
          • 执行过程
        • 无限循环
        • 嵌套循环
          • 练习1
          • 练习2
          • 练习3
          • 练习4
          • 练习5
          • 练习6
        • break和continue
          • break
          • continue
        • 标签
        • return
    • 数组

    • 面向对象

    • 异常处理

  • Java核心基础

  • 设计模式

  • Web开发

  • SpringBoot

  • 微服务

  • Elasticsearch

  • 运维

  • 后端
  • Java入门基础
  • 基本语法
SaulJWu
2020-12-06

流程控制-循环结构

# 前言

前面我们掌握了流程控制的分支结构,接下来学习流程控制的循环结构。

[TOC]

# 循环结构

在某些条件满足的情况下,反复执行特定代码的功能。

# 循环语句分类

  • for循环
  • while循环
  • do-while循环

在日常开发中,前面两种用得比较多。

# 组成部分

循环语句的四个组成部分:

  • 1.初始化部分(init_statement)
  • 2.循环条件部分(test_exp),指的是boolean类型
  • 3.循环体部分(body_statement)
  • 4.迭代部分(alter_statement)
20201206182748.png

# for循环

  • 1.初始化部分(init_statement)
  • 2.循环条件部分(test_exp),指的是boolean类型
  • 3.循环体部分(body_statement)
  • 4.迭代部分(alter_statement)

# 语法格式

for(① 初始化部分;② 循环条件部分;④ 迭代部分){
    ③ 循环体部分
}
1
2
3

# 执行过程

for循环的执行过程:1234,234,234,234……2

看下下面代码:

package forTest;

public class Demo1 {
    public static void main(String[] args) {
        int num = 1;
        for (System.out.print('a'); num <= 3; System.out.print('c'), num++) {
            System.out.print('b');
        }
    }
}
1
2
3
4
5
6
7
8
9
10

👆面代码的输出是

abcbcbc
1

注意上面的num是定义在for循环外,所以外面的作用域还是能获取到num值,如果定义在for循环里面,外界是获取不到的。

  • 比如:遍历100以内的偶数
package forTest;

public class Demo2 {
    public static void main(String[] args) {
        for (int i = 1; i <= 100; i++) {
            if (i % 2 == 0) {
                System.out.println(i);
            }
        }
        //System.out.println(i);这里无法获取i,编译无法通过。
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
  • 求1-100中所有偶数的和
package forTest;

public class Demo2 {
    public static void main(String[] args) {
        int total = 0;
        for (int i = 1; i <= 100; i++) {
            if (i % 2 == 0) {
                total += i;
            }
        }
        System.out.println(total);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

结果是:2550。

  • 在上面案例的基础上,输出偶数的个数
package forTest;

public class Demo2 {
    public static void main(String[] args) {
        int total = 0;
        int count = 0;
        for (int i = 1; i <= 100; i++) {
            if (i % 2 == 0) {
                total += i;
                count++;
            }
        }
        System.out.println("偶数之和:" + total + ",偶数个数:" + count);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

偶数之和:2550,偶数个数:50

# 练习1

遍历1-150,并在每行打印,3的倍数还要在数字后面打印“foo”,5的倍数还要追加打印“biz”,7的倍数还要追加“baz”。

package forTest;

/**
 * 遍历1-150,并在每行打印,3的倍数还要在数字后面打印“foo”,5的倍数还要追加打印“biz”,7的倍数还要追加“baz”。
 */
public class Demo3 {
    public static void main(String[] args) {
        for (int i = 1; i <= 150; i++) {
            System.out.print(i);
            if (i % 3 == 0) {
                System.out.print(" foo");
            }
            if (i % 5 == 0) {
                System.out.print(" biz");
            }
            if (i % 7 == 0) {
                System.out.print(" baz");
            }
            System.out.println();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

在工作当中,其实你可能一次性写出完美的代码很少,最好是写一点侧一点,不然写了一大堆,比如几千行,才开始测试代码,找bug都能找一天,所以还是写一部分,测一部分,反复修改,让程序完美健壮。

# break关键字

前面我们知道braek在switch-case的作用,其实break可以用在for循环中,它的作用是可以跳出循环。

随机两个正整数m和n(1-100),求最大公约数和最小公倍数。

package forTest;

/**
 * 随机两个正整数m和n(1-100),求最大公约数和最小公倍数。
 * 比如12和20的最大公约数是4,最小公倍数是60.
 */
public class Demo4 {
    public static void main(String[] args) {
        //用来存放最大公约数
        int k1 = 1;
        //用来存放最小公倍数
        int k2 = 0;
//        int m = (int) (Math.random() * 100 + 1);
//        int n = (int) (Math.random() * 100 + 1);
        int m = 12, n = 20;
        System.out.println("m=" + m + ",n=" + n);
        //最大公约数最大整除到m,n之间最小的数
        int min = m > n ? n : m;
        //从大到小开始遍历,开始整除,如果两个数都能整除遍历的这个数,那么这个数就是最大公约数
        for (int i = min; i >= 1; i--) {
            //最大公约数,都能够整除i
            if (m % i == 0 && n % i == 0) {
                System.out.println(i);
                System.out.println("m % i=" + (m % i));
                System.out.println("n % i=" + (n % i));
                k1 = i;
                break;
            }
        }
        System.out.println("最大公约数为:" + k1);
        //两个数的乘积 =这两个数的最大公约数 * 最小公倍数。
        //最小公倍数 =  两个数的乘积 / 这两个数的最大公约数
        k2 = m * n / k1;
        System.out.println("最小公倍数为:" + k2);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

最小公倍数的公式 (opens new window)

当然,也可以一个个遍历,去求最小公倍数

int max = m>n?m:n;
for(int i=max;i<=m*n;i++){
    if(i % m == 0 && i % n == 0){
		System.out.println("最小公倍数为:"+i);
        break;
    }
}
1
2
3
4
5
6
7

# 练习2

打印1~100之间所有奇数的和。

package forTest;

public class Demo5 {
    public static void main(String[] args) {
        int total = 0;
        for (int i = 1; i <= 100; i++) {
            if (i % 2 != 0) {
                total += i;
            }
        }
        System.out.println(total);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

结果是2500

# 练习3

打印1~100之间所有是7的倍数的整数的个数及总和。

package forTest;

public class Demo6 {
    public static void main(String[] args) {
        int total = 0;
        int count = 0;
        //打印1~100之间所有是7的倍数的整数的个数及总和。
        for (int i = 1; i <= 100; i++) {
            if (i % 7 == 0) {
                total += i;
                count++;
            }
        }
        System.out.println("total: " + total);
        System.out.println("count: " + count);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
total: 735
count: 14
1
2

# 练习4

输出所有的水仙花数,所谓水仙花数是指一个三位数,其各个位上数字立方和等于其本身。

package forTest;

/**
 * 输出所有的水仙花数,所谓水仙花数是指一个三位数,其各个位上数字立方和等于其本身。
 */
public class Demo7 {
    public static void main(String[] args) {
        for (int i = 100; i < 1000; i++) {
            //取出百位数
            int bai = i / 100;
            //取出十位数
            int shi = i / 10 % 10;
            //取出各位数
            int ge = i % 10;
            int total = (int) (Math.pow(bai,3) + Math.pow(shi,3) + Math.pow(ge,3));
            if (total == i) {
                System.out.println("个位数为:" + ge);
                System.out.println("十位数为:" + shi);
                System.out.println("百位数为:" + bai);
                System.out.println(i);
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
个位数为:3
十位数为:5
百位数为:1
153

个位数为:0
十位数为:7
百位数为:3
370

个位数为:1
十位数为:7
百位数为:3
371

个位数为:7
十位数为:0
百位数为:4
407
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# while循环

循环语句的四个组成部分:

  • 1.初始化部分(init_statement)
  • 2.循环条件部分(test_exp),指的是boolean类型
  • 3.循环体部分(body_statement)
  • 4.迭代部分(alter_statement)

# 语法格式

① 初始化部分(init_statement)
while(② 循环条件部分(test_exp)){
    ③ 循环体部分(body_statement);
    ④ 迭代部分(alter_statement);    
}
1
2
3
4
5

# 执行过程

while循环的执行过程基本上和for循环的一致,但是③和④的顺序都是可以自定义的。

# 注意点

  • 注意while循环千万小心不要丢了迭代条件,一旦丢了,可能导致死循环。我们写程序要避免死循环。
  • for循环和while循环是可以相互转换。

# 和for循环的区别

for循环和while循环的初始化条件部分的作用范围不同。

# do-while循环

循环语句的四个组成部分:

  • 1.初始化部分(init_statement)
  • 2.循环条件部分(test_exp),指的是boolean类型
  • 3.循环体部分(body_statement)
  • 4.迭代部分(alter_statement)

# 语法格式

① 初始化部分(init_statement)
do{
    ③ 循环体部分(body_statement);
    ④ 迭代部分(alter_statement); 
}while(② 循环条件部分(test_exp))
1
2
3
4
5

# 执行过程

① - ③ - ④ - ② 然后不停地③ - ④ - ② ……②

③和④的顺序可以交换。

do-while循环至少会执行一次循环体。

# 无限循环

最简单的“无限”循环格式:while(true),for(;😉,无限续航存在的原因是并不知道循环多少次,需要根据循环体内部某些条件,来控制循环的结束。

从键盘读入个数不确定的整数,并判读读入的整数和负数的个数,输入0时结束程序。

package forTest;

import java.util.Scanner;

/**
 * 从键盘读入个数不确定的整数,并判读读入的整数和负数的个数,输入0时结束程序。
 */
public class WhileTrueDemo {
    public static void main(String[] args) {
        //记录正整数个数
        int countA = 0;
        //记录负整数个数
        int countB = 0;
        Scanner scan = new Scanner(System.in);
        while (true) {
            System.out.println("请输入整数:");
            if (scan.hasNextInt()) {
                int input = scan.nextInt();
                if (input > 0) {
                    countA++;
                } else if (input < 0) {
                    countB++;
                } else {
                    System.out.println("程序结束!");
                    break;
                }
            } else {
                System.out.println("你输入的不是整数!");
                break;
            }
        }
        System.out.println("正整数累计个数为:" + countA);
        System.out.println("负整数累计个数为:" + countB);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

# 嵌套循环

嵌套循环,将一个循环结构A声明在另一个循环结构B的循环体中,就构成了嵌套循环。

业务场景中可能需要用到,但是一般建议不要超过3层,否则会增加代码复杂度。

两套嵌套循环的情况下,我们一般叫外面的循环为外层循环,里面的循环称为内层循环。

# 练习1

输出4行⭐,每行6个⭐

package forTest;

public class Demo8 {
    public static void main(String[] args) {
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 6; j++) {
                System.out.print("*");
            }
            System.out.println();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
******
******
******
******
1
2
3
4

# 练习2

输出4行⭐,从1个开始,每行多出一个⭐

package forTest;

public class Demo9 {
    public static void main(String[] args) {
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j <= i; j++) {
                System.out.print("*");
            }
            System.out.println();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
*
**
***
****
1
2
3
4

# 练习3

⭐⭐⭐⭐

⭐⭐⭐

⭐⭐

⭐

请打印此效果,用嵌套循环实现

分析:

i 行号 j ⭐个数
0 4
1 3
2 2
3 1

规律:i+j=4,那么每行⭐个数为:4-i

package forTest;

public class Demo10 {
    public static void main(String[] args) {
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4-i; j++) {
                System.out.print("*");
            }
            System.out.println();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

# 练习4

​ ⭐

​ ⭐⭐

​ ⭐⭐⭐

⭐⭐⭐⭐

⭐⭐⭐⭐⭐

⭐⭐⭐⭐

​ ⭐⭐⭐

​ ⭐⭐

​ ⭐

分析:

上半部分:

i 行号 空格个数 j ⭐个数
0 4 1
1 3 2
2 2 3
3 1 4
4 0 5

每行空格的个数为:4-i

下半部分:

i 行号 空格个数 j ⭐个数
0 1 4
1 2 3
2 3 2
3 4 1

事实上每一行都是5个字符串,只不过星星的数量不一样。而且只需要拆分为上半部分和下半部分就可以了。

package forTest;

public class Demo11 {
    public static void main(String[] args) {
        //上半部分
        for (int i = 0; i < 5; i++) {
            //输出空格
            for (int j = 0; j < 4 - i; j++) {
                System.out.print(" ");
            }
            //输出⭐
            for (int j = 0; j <= i; j++) {
                System.out.print("⭐ ");
            }
            System.out.println();
        }
        //下半部分
        for (int i = 0; i < 4; i++) {
            //输出空格
            for (int j = 0; j <= i; j++) {
                System.out.print(" ");
            }
            //输出⭐
            for (int j = 0; j <= 3-i; j++) {
                System.out.print("⭐ ");
            }
            System.out.println();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    * 
   * * 
  * * * 
 * * * * 
* * * * * 
 * * * * 
  * * * 
   * * 
    * 
1
2
3
4
5
6
7
8
9

# 练习5

输出一个九九乘法表

package forTest;

/**
 * 久久乘法表
 */
public class Demo12 {
    public static void main(String[] args) {
        int heng = 1;
        int shu = 0;
        while (true) {
            shu++;
            int ji = heng * shu;
            System.out.print(heng + " x " + shu + " = " + ji + " ");
            if (shu == heng) {
                heng++;
                shu = 0;
                System.out.println();
            }
            if (heng > 9) {
                break;
            }

        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

for循环的写法:

package forTest;

public class Demo13 {
    public static void main(String[] args) {
        for (int i = 1; i <= 9; i++) {
            for (int j = 1; j <= i; j++) {
                System.out.print(i + " x " + j + " = " + (i * j) + "  | ");
            }
            System.out.println();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

# 练习6

100以内所有质数的输出。质数,只能被1和它本身整除的自然数。

package forTest;

/**
 * 100以内所有质数的输出。质数,只能被1和它本身整除的自然数。
 * 最小的质数是2
 */
public class Demo14 {
    public static void main(String[] args) {
        for (int i = 2; i <= 100; i++) {
            boolean flag = true;
            for (int j = 2; j < i; j++) {
                if (i % j == 0) {
                    flag = false;
                    break;
                }
            }
            if (flag) {
                System.out.println(i);
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

把数据扩大1000倍,对比一下,不存在break关键字和存在break关键字花费时间

package forTest;

/**
 * 100以内所有质数的输出。质数,只能被1和它本身整除的自然数。
 * 最小的质数是2
 */
public class Demo15 {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        int count = 0;
        for (int i = 2; i <= 100000; i++) {
            boolean flag = true;
            for (int j = 2; j < i; j++) {
                if (i % j == 0) {
                    flag = false;
//                    break;
                }
            }
            if (flag) {
                System.out.println(i);
                count++;
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("质数个数为:" + count);
        System.out.println("花费毫秒:" + ( end-start));
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
99907
99923
99929
99961
99971
99989
99991
1
2
3
4
5
6
7

质数个数为:9592,花费时间17054毫秒

打开break关键字,质数个数为:9592,花费时间1592毫秒,省了将近10倍。

那么还能优化代码吗?

其实根本不用整除每一个数,只需要整除i的根号就可以了,为什么?

假设存在一个数96,其实我们知道它可以整除2,所以绝对不是质数。

96能整除2,那肯定能整除48。

能整除3,那肯定能整除32

能整除4,那肯定能整除24

……

能整除6,那肯定能整除16.

能整除的数它们是一对对的,两端都有一个能整除的数字,那么那个临界点就是96的平方根,我只需要遍历到它的平方根,就可以知道了,不用再去重复验证了。

package forTest;

/**
 * 100以内所有质数的输出。质数,只能被1和它本身整除的自然数。
 * 最小的质数是2
 */
public class Demo15 {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        for (int i = 2; i <= 100000; i++) {
            boolean flag = true;
            for (int j = 2; j <= Math.sqrt(i); j++) {
                if (i % j == 0) {
                    flag = false;
                    break;
                }
            }
            if (flag) {
                System.out.println(i);
                count++;
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("质数个数为:" + count);
        System.out.println("花费毫秒:" + ( end-start));
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
99877
99881
99901
99907
99923
99929
99961
99971
99989
99991
质数个数为:9592
花费毫秒:47
1
2
3
4
5
6
7
8
9
10
11
12

第一次未优化时间:17054毫秒

第二次优化时间:1592毫秒

第三次优化时间:47毫秒。

# break和continue

关键字 使用范围 作用
break switch-case和循环结构中 结束当前循环
continue 循环结构中 结束当次循环

可以看出2个关键字都是用来中断循环,不同的是break是结束循环后,退出了,而continue是跳过剩余执行语句,进入下一次循环。

无论break还是continue关键字后面不能声明执行语句,编译不通过。

# break

for(int i=1;i<10;i++){
    if(i % 4 == 0){
        break;
    }
    System.out.println(i);
}
1
2
3
4
5
6
123
1
  • 嵌套和break

在嵌套循环中,break默认结束包裹此关键字最近的一层循环。

# continue

for(int i=1;i<10;i++){
    if(i % 4 == 0){
        continue;
    }
    System.out.println(i);
}
1
2
3
4
5
6
1235679
1

# 标签

对Java 来说,唯一用到标签的地方是在循环语句之前。进一步说,它实际需要紧靠在循环语句的前方——在

标签和循环之间置入任何语句都是不明智的。而在循环之前设置标签的唯一理由是:我们希望在其中嵌套另

一个循环或者一个开关。这是由于 break 和 continue 关键字通常只中断当前循环,但若随同标签使用,它们

就会中断到存在标签的地方。

“标签”是后面跟一个冒号的标识符。

例如:

label:for(int i=1;i<=4;i++){
    label2:for(int j=1;j<=10;j++){
       if(j % 4 == 0){
       		break label1;
       } 
    }
    System.out.println(i);
}
1
2
3
4
5
6
7
8

或者

label1:for(int i=1;i<=4;i++){
    label2:for(int j=1;j<=10;j++){
       if(j % 4 == 0){
       		continue label1;
       } 
    }
    System.out.println(i);
}
1
2
3
4
5
6
7
8

在嵌套循环中,如果break或continue不指定关键字,默认结束包裹此关键字最近的一层循环。

package forTest;

/**
 * 100以内所有质数的输出。质数,只能被1和它本身整除的自然数。
 * 最小的质数是2
 */
public class Demo16 {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        int count = 0;
        label:for (int i = 2; i <= 100000; i++) {
            boolean flag = true;
            for (int j = 2; j <= Math.sqrt(i); j++) {
                if (i % j == 0) {
                    continue label;
                }
            }
            count++;
        }
        long end = System.currentTimeMillis();
        System.out.println("质数个数为:" + count);
        System.out.println("花费毫秒:" + ( end-start));
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
质数个数为:9592
花费毫秒:14
1
2

# return

  • return:并非专门用于结束循环的,它的功能是结束一个方法,并且返回数据。当一个方法执行了return,这个方法将结束
  • 与break或者continue不同的是,return直接结束整个方法,不管这个return处于多少层循环之内。
帮我改善此页面 (opens new window)
#for#while#do#break#continue
上次更新: 2020/12/18, 12:50:58
流程控制-分支结构
数组

← 流程控制-分支结构 数组→

最近更新
01
zabbix学习笔记二
02-28
02
zabbix学习笔记一
02-10
03
Linux访问不了github
12-08
更多文章>
Theme by Vdoing | Copyright © 2020-2022 Saul.J.Wu | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式