精品专题:
01.《C语言从不挂科到高绩点》课程详细笔记
https://blog.csdn.net/yueyehuguang/category_12753294.html?spm=1001.2014.3001.5482
02. 《SpringBoot详细教程》课程详细笔记
https://blog.csdn.net/yueyehuguang/category_12789841.html?spm=1001.2014.3001.5482
03.《SpringBoot电脑商城项目》课程详细笔记
https://blog.csdn.net/yueyehuguang/category_12752883.html?spm=1001.2014.3001.5482
04.《VUE3.0 核心教程》课程详细笔记
https://blog.csdn.net/yueyehuguang/category_12769996.html?spm=1001.2014.3001.5482
================================
|| 持续分享系列教程,关注一下不迷路 ||
|| 视频教程:小破站:墨轩大楼 ||
================================
3. 循环语句
3.1. 循环概述
在java中程序的执行流程,除了顺序结构,分支结构之外,还有另一种非常常见的结构:循环结构;在对于某些需要反复执行的操作执行时,需要使用到循环,对于某些容器(数组,集合)遍历操作时也需要使用到循环,循环在实际的生产开发环境中应用十分广泛;Java中对于循环的支持,包含以下分类:
- for循环
- while循环
- do..while循环
- 迭代器:forEach
- 递归(recursion)
有关循环语句的执行流程:
3.2. for循环
for循环是一种经典循环方式,for循环一般常见于循环次数已知的应用场景中,语法规则:
for(初始值;循环条件;步进){
//循环体
}
for(int i=1;i<=10;i++){
int n = (int)(Math.random()*10) + 1;
System.out.println(n);
}
3.3. while循环
除了for之外,java中对与一些循环次数不定的操作也提供了while循环来实现,while循环的执行次数为0次~N次,语法规则:
while(循环条件){
//循环体
}
int i = 1;
while(i <= 10){
System.out.println(i);
i++;
}
3.4. do...while循环
while循环除了传统写法之外,对于一些特殊的需求还提供了另一种使用方式:do..while;doWhile循环至少会执行一次,最多N次;语法:
do{
//循环体
}while(循环条件)
do{
System.out.println(i);
i++;
}while(i<=10);
3.5. 循环练习
1. 求1+2+3+4+...100=? 考虑临时变量(局部变量)
2. 求 5! = 5*4*3*2*1
3. 打印1000以内的所有偶数
//1000以内的所有偶数
for (int i = 0; i <= 1000 ; i+=2) {
System.out.print(i+" ");
}
System.out.println();
//请输出1000以内5的倍数
for (int i = 0; i <= 1000 ; i+=5) {
System.out.print(i+" ");
}
4. 求水仙花数(一个三位数,每一位的立方和都是这个数本身:xyz = x*x*x + y*y*y + z*z*z)
for (int i = 100; i < 1000; i++) {
int a = i % 10; //个位
int b = i / 10 % 10; //十位
int c = i / 100; //百位
if (a * a * a + b * b * b + c * c * c == i) {
System.out.println("水仙花数:" + i);
}
}
4. 扩展:系统输入
通常情况下需要输出数据到控制台我们可以使用System.out(标准输出流)完成,控制台除了可以实现系统输出外同时也支持系统输入System.in(标准输入流);JDK中提供了一个类java.util.Scanner可以实现对标准输入流进行扫描以及读取流中的内容,并且Scanner类还可以将不同的数据扫描读取为不同的数据类型。
Scanner常用方法:
- next():以空格作为标记读取一段文本内容,返回String类型
- nextInt():以空格作为标记读取一个整数,返回为int类型
- nextLine():以换行符作为结束标记,读取一行文本内容,返回String类型
//创建文本扫描对象用于从标准输入流中获取信息(引用数据类型)
Scanner sc = new Scanner(System.in);
//从下一个结束标记(空格)之前扫描一段文本信息(阻塞式)
String s = sc.next();
System.out.println("输入的内容是:"+s);
//读取下一个扫描到的内容并识别为int类型,结束标记为空格
int i = sc.nextInt();
System.out.println("输入的整数是:"+i);
sc.nextLine(); //读取一个空行
System.out.println("================");
//以换行作为结束标记
s = sc.nextLine();
System.out.println("输入的一行内容是:"+s);
思考题
模拟地下城与勇士(DNF)的装备强化过程:
提示1:
- DNF装备强化在+1~+3 不会失败;
- +4~+7,失败后物品原有强化等级降低1级;
- +8~+10,失败后掉3级;
- 10上11或以上失败就爆了。
提示2:
- DNF装备强化1~3级,成功率100%
- DNF装备强化3~4级,成功率95%
- DNF装备强化4~5级,成功率90%
- DNF装备强化5~6级,成功率80%
- DNF装备强化6~7级,成功率75%
- DNF装备强化7~8级,成功率62.1%
- DNF装备强化8~9级,成功率53.7%
- DNF装备强化9~10级,成功率41.4%
- DNF装备强化10~11级,成功率33.9%
- DNF装备强化11~12级,成功率28%
- DNF装备强化12~13级,成功率20.7%
- DNF装备强化13~14级,成功率17.3%
- DNF装备强化14~15级,成功率13.6%
- DNF装备强化15~16级,成功率10.1%
实现流程:
要求输入装备的原始等级,输入1执行强化,根据原始等级以及强化的成功率,显示装备的强化结果
public static void add(int initLevel){
//TODO 实现过程
}
5. 死循环
在使用循环过程中,经常会因为忽略一些关键的实现细节导致程序出现死循环(death loop);死循环往往是因为没为循环设置一个结束条件,或者是设置了一个无法达到的结束条件而导致;
例如:
for(int i = 0;i >= 0;i++){
System.out.println(i);
}
死循环将会导致程序一直执行,消耗大量的内存空间,影响程序的执行性能,尽量要避免死循环的产生。
另外有些时候使用死循环也能满足一些实际的需求:
for(;;){
Scanner sc = new Scanner(System.in);
System.out.print("请输入数字:");
int n = sc.nextInt();
System.out.println("您输入的是:"+n);
}
以上的死循环使用while一样可以实现
while(true){
Scanner sc = new Scanner(System.in);
System.out.print("请输入数字:");
int n = sc.nextInt();
System.out.println("您输入的是:"+n);
}
6. 嵌套循环
6.1. 概述
java中除了支持单层的循环之外,另外也支持在循环中嵌套其他循环,实际开发中应尽可能避免循环的嵌套(会导致内存的开销,影响程序性能);但是有些业务中也必须使用嵌套循环来实现具体功能,例如对二维数组的遍历,对多级菜单的遍历等。
嵌套循环的执行流程图:
for(int i = 1;i<10;i++){
for(int j = 10;j<20;j++){
System.out.println(i+"----"+j);
}
}
- 练习题:输出一个九九乘法口诀表
1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
...
6.2. 嵌套循环练习
- 请使用嵌套循环输出以下图形:
*
***
*****
*******
- 打印菱形
*
***
*****
*******
*****
***
*
- 打印平行四边形
********
********
********
********
********
7. 循环中断
在循环语句正常执行过程中一般没有任何异常情况下,循环会根据结束条件的满足而自然结束,但是某些情况可能需要提前中断循环(不是终止虚拟机);对于这种需求,java中提供了break和continue关键字用于结束(跳过)循环。
例如:输出1000以内,跳过5的倍数输出其他数值。
7.1. continue
continue关键字,在实际使用场景中出现的比较少,一般用在循环内部,用于跳过N次循环中的某一次循环,例如:
for (int i = 0; i < 1000; i++) {
if(i % 5 == 0){
//当条件满足时执行continue,跳过本次循环,开始下一次循环
continue;
}
System.out.println(i);
}
以上的运行结果除了5的倍数之外,输出其他的所有小于1000数值
7.2. break
break关键字的使用场景除了在switch语句中用于防止case穿透之外,另外也可以用于循环语句中终止循环,break用在循环中可以结束一层循环。例如:
for (int i = 0; i < 10; i++) {
for (int j = 10; j < 20; j++) {
if(j % 6 == 0){
break;
}
System.out.print(i+","+j+" ");
}
System.out.println();
}
0,10 0,11
1,10 1,11
2,10 2,11
3,10 3,11
4,10 4,11
5,10 5,11
6,10 6,11
7,10 7,11
8,10 8,11
9,10 9,11
观察以上输出结果,能够直观的发现,当内层循环的变量跟6取余能除尽时,内层循环则直接中断
面试题:continue、break、return关键字的区别?
- continue主要用于循环语句中,结束一次循环
- break用于switch语句中防止case穿透;还可以用于循环语句中结束一层循环
- return用于方法中结束方法,return之后跟随具体的值或者变量用于返回方法的返回值;如果不跟任何内容则表示结束方法
7.3. 循环标记
在某些情况,循环嵌套层次比较多的时候,需要通过break、continue结束(跳过)指定层的循环,可以使用循环标记来完成,循环标记就是为每一个循环语句块添加一个标签,然后在结束时,相关的关键字后面跟上标记就可以实现:
loop1:for (int i = 0; i < 10; i++) {
loop2:for (int j = 10; j < 20; j++) {
if(j % 6 == 0){
break loop1;
}
System.out.print(i+","+j+" ");
}
System.out.println();
}
System.out.println("程序结束");
以上程序中的loop1和loop2就是循环标签(标签可以自定义:只需要符合标识符的命名规范就可以)
8. 递归(recursion)
8.1. 概述
递归是反复执行代码的另一种方式,区别于传统的循环,原理是在方法层面,对方法自身调用,通过递归可以解决一些循环所解决不了的问题(例如:文件夹的递归遍历,树形菜单的动态展示等),另外使用递归也能解决一些常见的算法问题,例如:斐波拉契数列,汉诺塔等。
递归语法:
修饰符 返回值类型 方法名(){
方法名();
}
在一个方法中对当前方法进行调用即称之为递归:
public void m(){
system.out.println("方法执行");
m();
}
注意事项:
如果不为递归方法指定结束条件,则程序将会导致StackOverflowerError出现:
Exception in thread "main" java.lang.StackOverflowError
at com.softeem.day4.recursion.Demo1.sum(Demo1.java:13)
at com.softeem.day4.recursion.Demo1.sum(Demo1.java:13)
at com.softeem.day4.recursion.Demo1.sum(Demo1.java:13)
at com.softeem.day4.recursion.Demo1.sum(Demo1.java:13)
...
8.2. 案例
- 求1+2+3+4+...+100=?上述问题除了使用传统循环解决之外,使用递归也能轻松实现:
public class Demo1 {
public static int sum(int n){
if(n <= 1){
return 1;
}else{
//方法递归调用
return n + sum(n-1);
}
}
public static void main(String[] args) {
System.out.println(sum(100)); // 5050
}
}
原理如下:
- 求5!
/**
* 5*4*3*2*1
*
* @param n
* @return
*/
public static int jiecheng(int n) {
if (n == 1) {
return 1;
} else {
return jiecheng(n - 1) * n;
}
}
8.3. 思考题
请观察以下的数列,寻找规律
1 1 2 3 5 8 13 21 34 ... n
求n的结果(斐波拉契数列)
public static int fib(int n){
if(n == 1 || n == 2){
return 1;
}else{
return fib(n-1) +fib(n - 2);
}
}
练习
- 实现汉诺塔(递归实现)
- 实现一个动态日历提示:
提示:
1. 平年2月份是28天,闰年2月份是29天;1,3,5,7,8,10,12这几个月是31天,其余的每个月(4,6,9,11)30天
2. 计算从1900年1月到当前月份的上一个月总天数
3. 总天数和7取余之后,余数则为当月前面需要输出的空格(建议使用制表符:tab)数