1 循环流程控制
1.1 循环流程控制概述
1.1.1 什么是循环流程控制
当一个业务过程需要多次重复执行一个程序单元时,可以使用循环流程控制实现。
Java中包含3种循环结构:
1.2 for循环
1.2.1 for循环基础语法
for循环是最常用的循环流程控制,用于将某个语句或语句块重复执行预定次数的情形。语法如下:
for ( 表达式1;表达式2;表达式3 ) {
语句块(循环体)
}
可以看出,for循环的三个表达式之间通过分号;进行分隔,其执行逻辑如下所示:
1、计算表达式1的值,通常为循环变量赋初值;
2、计算表达式2(表达式2为逻辑表达式)的值,即判断循环条件是否为真,若值为真则执行循环体一次(语句块),否则跳出循环;
3、执行循环体;
4、计算表达式3的值,此处通常写更新循环变量的赋值表达式;
5、计算表达式2的值,若值为true则执行循环体,否则跳出循环;
6、如此循环往复,直到表达式2的值为false。
1.2.2 固定次数的循环
for循环常常用于解决固定次数循环的处理,比如说逐一打印从1到10的数字,固定执行10次;比如求累加和,想求1+2+3+…+100的结果,次数固定执行100次。
作为计次循环使用时候,关键要找到其4个要素:
- 初始化
- 循环条件(结束)
- 递增/递减
- 循环体
执行流程如下所示:
比如,从 0 开始,逐行输出0、1、2、3,for循环工作流程如下所示:
1.2.3 【案例】累加求和
计算从1累加到100的和,并输出计算结果。考虑使用for循环处理,执行过程如下所示:
案例示意代码如下:
public class ForDemo1 {public static void main(String[] args) {int sum = 0;for (int i = 1; i <=100; i++) {sum = sum + i; // sum+=i}System.out.println(sum);}
}
分析上面代码的执行过程:
1、声明一个变量用于保存累加和,此变量命名为sum,赋初始值为0;
2、for循环从1开始,每次增1,执行100次,循环体中将i的值累加到sum变量中。注意:每次都是在sum的基础之上加上i,所以使用了sum += i。
3、循环结束后,输出结果。
1.2.4 【案例】输出100以内所有13的倍数
寻找100以内所有13的倍数,并逐一输出。
可以从1开始循环到100,逐一判断,代码示意如下:
public class ForDemo2 {public static void main(String[] args) {for(int i = 1; i <= 100;i++) {if (i%13 == 0){System.out.print(i+" ");}}}
}
也可以直接从13开始循环到100,每次循环增加13,代码示意如下:
public class ForDemo2 {public static void main(String[] args) {for(int i = 13; i <= 100;i += 13) {System.out.print(i+" ");}}
}
1.2.5 break语句
break可用于循环语句或switch语句中。break用于循环,可使程序终止循环而执行循环后面的语句,常常与条件语句一起使用。
1.2.6 【案例】for循环与break
需要统计1到100的累加和,条件是当和大于等于4000时则终止计算,输出所计算的累加和。
此案例通过在if语句中使用break实现了for语句的退出,分析过程如下:
本程序最终sum的值为:4005。
代码示意如下:
public class BreakDemo {public static void main(String[] args) {int sum = 0;for(int i = 1; i <=100; i++) {if (sum >= 4000){break;}sum += i;}System.out.println(sum);}
}
1.2.7 continue语句
continue只能用于循环中,其作用为跳过循环体中剩余语句而执行下一次循环。
比如需要逐一输出1到100之间的整数,但是遇到7的倍数或者以7结尾的数字,则不需要输出。代码及分析如下:
1.2.8 【案例】for循环与continue
有一个游戏名为“查 7“:从1到100,逐一念出数字,如果遇到7的倍数或者含7的数字,则跳过。比如 7、14、17、21等都需跳过。
用代码实现“查7游戏”:输出 1 到 100 之间非7的倍数以及不含7的数字。
代码示意如下:
public class ContinueDemo {public static void main(String[] args) {for(int i = 1; i <= 100; i++) {if (i%7 == 0 || i%10 ==7 || i/10 == 7) {continue;}System.out.println(i);}}
}
1.2.9 循环变量的作用域
for循环中的变量,其有效用域为for循环内部。这样可以减少变量的冲突,实现循环变量的复用。
查看如下代码:
上下两个循环中,都可以使用名为 i 的变量,并不会产生错误。这是因为每个变量 i 都是在 for 循环内部定义,也只在 for 循环内部有效。
1.2.10 for循环省略初始化表达式
省略for循环的初始化表达式,则需要在for循环外定义变量,代码示意如下:
通过上面的代码可以看出,虽然省略了初始化表达式1,但只是将它放在了for循环的外面进行声明,只是位置不同而已。这样可以扩大循环变量作用范围,也可以在多个循环间共享循环变量。
在此需要注意一点,即使for语句中不写表达式1了,表达式2前面的分号;也不能省略。
1.2.11【案例】 for循环变量示例
测试for循环变量的作用域:
- for 循环内部定义
- 省略初始化表达式
代码示意如下:
public class ForDemo3 {public static void main(String[] args) {for(int i=0; i<=3; i++) {//i = 0 1 2 3System.out.print(i+"-");}System.out.println();for(int i=0; i<=4; i++) {//i = 0 1 2 3System.out.print(i+"-");}//System.out.println(i); //编译错误,没有变量iSystem.out.println();//利用i实现两个循环接力处理int i = 0;for ( ; i<=3 ; i++ ) {//i= 0 1 2 3System.out.print(i+"-");}//System.out.println(i); //4for( ; i<=5 ; i++ ) {//i = 4 5System.out.print(i+"+");}System.out.println(i); //6}
}
1.2.12 for循环省略循环条件
for循环可以省略循环条件,省略循环条件以后,当需要结束循环时,则可以利用break退出循环。代码示意如下:
for(int i=0; ;i++){System.out.print(i);if(i==10){break; //退出循环}
}
1.2.13 for循环省略表达式3
for循环可以省略表达式3,这时可以在循环体中控制循环变量的值,进而控制循环结束。代码示意如下:
for(int i=0; i<=10; ){System.out.print(i++);
}
通过上面的代码可以看出,虽然省略了表达式3,但也只是将它放在了for循环体之中,只是位置不同而已。在此需要注意一点,即使for语句中不写表达式3了,表达式2后面的分号;也不能省略。
for循环也可以省略全部的表达式,只留下循环体,此时for循环是“死”循环,需要在循环中适当的添加break语句结束循环。代码示意如下:
long timeout=System.currentTimeMillis()+1000;
for( ; ; ){System.out.println(“我爱学Java");if(System.currentTimeMillis() > timeout){break;}
}
1.2.14 for循环与逗号表达式
for循环中可以定义多个循环变量,实现复杂控制:使用逗号表达式来定义多个循环变量。这样可以控制多个变量的作用域,使变量只在for循环内部有效。
逗号表达式也是运算符,多个表达式用逗号连接构成逗号表达式。
查看如下代码示例:
for ( int i =1 , j = 6 ; i <= 6 ; i +=2 , j -=2 ) {
System.out.println(“ i , j = “ + i + “,” + j );
}
上面的代码的执行逻辑如下:初始设置i为1,j为6,判断i是否小于等于6,为真则执行循环体,而后执行i+=2,j-=2,即:i增2,j减2。再判断i是否小于等于6,为真继续执行循环体,以此类推,直到条件为false。本程序的输出结果为:
1.3 while和do…while
1.3.1 while 循环
经典for循环一般用于处理处理计次循环,不计次循环一般采用while/do-while。其语法如下:
while( 循环条件 ) {循环体;
}
其执行流程为:
- 计算“循环条件”表达式的值
- 如果值为true则执行“循环体”
- “循环体”执行完后再次判断“循环条件”表达式的值,如果为true则继续执行“循环体”
- 如此循环往复,直到“循环条件”为false时结束while循环
执行示意图如下所示:
用while循环关键是找到两个要素:
- 循环体
- 循环条件
1.3.2 【案例】while 循环示例
用代码模仿摇骰子(dice)游戏:三个骰子一起摇,摇到一个“豹子”就结束。“豹子”是指3个骰子点数相等情况。分析执行逻辑如下:
此案例中,需要使用 Random产生随机数。代码示意如下:
import java.util.Random;
public class WhileDemo1 {public static void main(String[] args) {int dice1 = 1;int dice2 = 2;int dice3 = 3;Random random = new Random();while(dice1!=dice2 || dice1!=dice3) {dice1 = random.nextInt(7-1)+1;dice2 = random.nextInt(7-1)+1;dice3 = random.nextInt(7-1)+1;System.out.println(dice1+","+dice2+","+dice3);}}
}
1.3.3 do…while 循环
do-while也是循环的一种常见语法结构,其语法如下:
do {循环体;
} while( 循环你条件 ) ;
其执行流程为:
- 先执行“循环体”
- 再计算“循环条件”表达式的值:如果为true,再次执行“循环体”
- 如此循环往复,直到“循环体”表达式的值为false为止
示意如下:
1.3.4 【案例】do…while 循环示例
用代码模拟“猜数字“游戏:
- 程序随机生成并存储一个100以内的正整数n
- 用户输入一个整数,程序判断与 n 的大小比较,输出“大”或“小”的比较结果提示
- 直到用户猜对数字,则输出“猜中了”
业务分析如下:
代码示意如下:
import java.util.Scanner;
public class DoWhileDemo1 {public static void main(String[] args) {Scanner console = new Scanner(System.in);//生存随机数int num = (int)(Math.random()*100);System.out.println("开始猜猜吧!");int guess;do{guess = console.nextInt();if(guess>num) {System.out.println("猜大了!");}if(guess<num) {System.out.println("猜小了!");}if(guess==num) {System.out.println("猜中了!");}}while(guess!=num);}
}
1.3.5 关于while和do…while
while 和 do…while 都是不定次数循环,其区别为:
- while结构:先“循环条件”后执行“循环体”,有可能循环体一次都不执行
- do…while结构:先执行“循环体”后执行“循环条件”,至少执行一次“循环体”
流程对比如下:
1.4 循环问题
1.4.1 循环问题定义:“当”循环
如果业务可以转换为“当……“这样的句式时,优先选择while语句来实现。看下面的需求:假设年存款利率为3%,本金为10000,问存款总额超过12000时,收益具体是多少?
分析这个需求,可以转化为下面的理解:“当“存款总额小于12000时,以3%的利率增长,那么条件就是total<12000,这种”当“句式优先考虑使用while语句实现,简易代码如下:
……
while( 条件 ) {
total += ( total * 0.03 ) ;
}
……
1.4.2 循环问题定义:“直到”循环
如果业务可转换为”直到……”这样的句式时,优先选择do-while语句来实现。看下面的需求:在验证身份时必须提供密码并核对,密码不正确则继续输入密码。分析这个需求,可以转化为下面的理解:获取密码,”直到”输入的值为123456,那么条件就是! ”123456”.equals(inputPwd),这种“直到……“句式优先考虑使用do-while语句实现,简易代码如下:
……
do {
……
} while(! ”123456”.equals(inputPwd));
……
1.4.3 循环问题定义:固定次数循环
如果业务中可以获取到一个确切的循环次数时可以考虑使用for循环来实现,看下面的需求:求1-100的和、累加10次输入的数字的和、录入3名学员信息、存储5门课程成绩……,上面的需求都是可以明确确切的循环次数,故而优先用for循环。
在前面所介绍的3种循环(while、do-while、for)中,一般情况下,for循环使用得最多,而对于for循环结构,一定要分析出需要解决业务的三个部分:
- 循环变量初始状态
- 循环条件
- 循环变量的改变
分析好了上面的三个部分,for语句的结构也就定义好了,其它的问题只在于填写不同的循环体来解决不同的业务问题而已。
1.5 嵌套循环
1.5.1 嵌套循环
嵌套循环是指在一个循环的循环体中添加另一个循环,常用于执行复杂的循环流程控制。
1.5.2 【案例】打印直角三角形
在控制台打印输出5行的直角三角形,输出效果如下:
代码示意如下:
public class ForDemo4 {public static void main(String[] args) {for(int i = 1 ; i <= 5;i++){//外层循环for(int j = 1 ; j <= i;j++){//内层循环System.out.print("*");}System.out.println();}}
}
2 数组
2.1 基本类型数组
2.1.1 什么是数组
在Java中,数组是一种用于存储相同类型数据元素的数据结构。它是一系列按照顺序排列的元素集合,可以通过索引访问每个元素。
以一个简单的例子来解释,假设你想存储一组学生的分数。如果你使用分离的变量来存储每个学生的分数,你需要为每个学生声明一个独立的变量。这可能会导致代码冗长而难以管理,特别是当学生数量很大时。
相反,使用Java数组,你可以创建一个包含学生分数的数组。例如,你可以声明一个名为"scores"的整数数组,然后将每个学生的分数存储在该数组的不同索引位置上。这样一来,你只需要一个变量来表示所有学生的分数,并且可以通过索引轻松访问和操作每个学生的分数。
Java数组的好处包括:
- 容易访问和操作元素:通过索引,可以直接访问数组中的任何元素,而不需要遍历整个数组。这使得对数组进行排序、搜索或修改等操作更加高效和方便。
- 代码简洁和可读性强:相对于分离的变量,使用数组可以更清晰地表示一组相关数据。这样可以减少变量的数量,使代码更简洁、易于理解和维护。
- 循环处理方便:通过循环结构,可以轻松地遍历数组中的所有元素,执行相同的操作或获取相应的结果。这对于处理大量数据的情况非常有用。
- 内存管理效率高:数组在内存中是连续存储的,这意味着访问数组的任何元素时,可以通过简单的数学计算直接找到其位置。这提供了高效的内存访问和管理。
需要注意的是,Java数组的大小在创建时是固定的,无法动态调整。需要通过变通算法进行处理。
2.1.2 创建基本类型数组
在Java中,创建基本类型数组的语法非常简单。定义数组的语法为:数据类型[] 数组名 = new 数据类型 [ 大小 ]。
以下是创建不同基本类型数组的示例:
创建整数数组:int[] numbers = new int[5]; // 创建一个包含5个整数的数组
创建浮点数数组:float[] values = new float[10]; // 创建一个包含10个浮点数的数组
创建布尔类型数组:boolean[] flags = new boolean[8]; // 创建一个包含8个布尔值的数组
创建字符数组:char[] letters = new char[26]; // 创建一个包含26个字符的数组
创建字节类型数组:byte[] data = new byte[100]; // 创建一个包含100个字节的数组
这些示例演示了如何声明基本类型数组,并通过指定数组大小来分配内存空间。在上述示例中,方括号"[]"用于指示创建的变量是一个数组。括号内的数字表示数组的大小,即数组可以存储的元素数量。
2.1.3 基本类型数组默认值
当创建基本类型数组时,数组的每个元素将被初始化为基本类型的默认值。下面是各个基本类型数组的默认值:
- 整数类型(如int、byte、short、long):0
- 浮点数类型(如float、double):0.0
- 布尔类型(boolean):false
- 字符类型(char):空字符('\u0000'),这是一个控制字符,直接打印输出时不可见
因此,如果你创建一个int类型的数组,所有元素的初始值将为0;如果创建一个boolean类型的数组,所有元素的初始值将为false。需要注意的是,这些初始值是默认值,可以在之后的代码中进行修改。
这些默认值对于基本类型数组的初始化很有用,因为它们确保在使用数组元素之前,每个元素都具有一个已知的初始值。如果需要指定特定的初始值,可以在创建数组后使用循环或逐个赋值的方式进行初始化。
数组的默认值如下图所示:
2.1.4 访问数组元素
创建数组后,可以通过索引访问和操作数组中的元素。索引从0开始,依次递增。这意味着第一个元素的索引为0,第二个元素的索引为1,以此类推。以下是访问和赋值数组元素的示例:
int[] numbers = new int[5]; // 创建一个包含5个整数的数组
// 访问和赋值数组元素
numbers[0] = 10; // 将10赋值给第一个元素
int x = numbers[1]; // 将第二个元素的值赋给变量x
numbers[2] += 5; // 将第三个元素的值增加5
// 输出数组元素的值
System.out.println(numbers[0]); // 输出第一个元素的值
System.out.println(numbers[1]); // 输出第二个元素的值
System.out.println(numbers[2]); // 输出第三个元素的值
在上述示例中,我们创建了一个包含5个整数的数组numbers。然后,我们通过索引访问和赋值数组元素。例如,numbers[0] = 10;将10赋值给数组的第一个元素。我们还可以将数组元素的值赋给其他变量,如int x = numbers[1];。最后,我们通过System.out.println()语句输出数组元素的值。
需要注意的是,索引必须在有效范围内,即从0到数组长度减1。访问超出范围的索引将导致ArrayIndexOutOfBoundsException异常。因此,在访问数组元素之前,应确保使用的索引是有效的。
2.1.5使用元素初始化数组
当使用长度创建数组时,数组的每个元素将被初始化为基本类型的默认值。然而,如果我们已经知道要存储的具体元素值,我们可以在创建数组时直接使用这些元素来初始化数组。这种方式称为使用元素初始化数组。
以下是使用元素初始化数组的示例:
int[] numbers = {10, 20, 30, 40, 50}; // 使用元素初始化整数数组
float[] values = {1.5f, 2.7f, 3.8f}; // 使用元素初始化浮点数数组
boolean[] flags = {true, false, true}; // 使用元素初始化布尔类型数组
char[] letters = {'A', 'B', 'C', 'D'}; // 使用元素初始化字符数组
在上述示例中,我们使用花括号({})来指定数组的元素,并将它们按顺序放置在大括号中。每个元素之间用逗号分隔。通过这种方式,我们可以在创建数组时直接为每个元素赋予特定的值。
使用元素初始化数组可以让我们更简洁地创建数组并为其赋值。这种方式适用于我们已经知道要存储的元素值,并且不需要改变数组大小的情况。
2.1.6【案例】基本类型数组示例
下面是一个基本类型数组示例,涵盖了创建基本类型数组、测试数字默认值、访问数组元素、使用元素初始化数组和访问数组元素的过程:
public class ArrayExample {public static void main(String[] args) {// 创建整数数组int[] numbers = new int[5];// 测试数字默认值System.out.println(numbers[0]); // 输出第一个元素的默认值,0// 访问和赋值数组元素numbers[0] = 10;numbers[1] = 20;numbers[2] = 30;numbers[3] = 40;numbers[4] = 50;// 输出数组元素的值System.out.println(numbers[0]); // 输出第一个元素的值,10System.out.println(numbers[2]); // 输出第三个元素的值,30System.out.println(numbers[4]); // 输出最后一个元素的值,50// 使用元素初始化数组int[] newNumbers = {1, 2, 3, 4, 5};// 访问和输出新数组的元素值System.out.println(newNumbers [0]);System.out.println(newNumbers [1]);}
}
在上述示例中,我们首先创建了一个整数数组 numbers,长度为5。使用 System.out.println(numbers[0]); 输出第一个元素的默认值,即0。
然后,我们通过索引访问和赋值数组元素。将具体的值分别赋给数组元素。
接着,我们输出数组元素的值,使用 System.out.println() 分别输出第一个、第三个和最后一个元素的值。
接下来,我们使用元素初始化数组,通过 {} 花括号将元素包围,直接为新数组的元素赋值。
最后,通过 System.out.println() 输出新数组元素的值。
通过这个示例,我们展示了基本类型数组的创建、默认值、访问和赋值、使用元素初始化以及遍历访问数组元素的过程。这些操作允许我们存储和操作一系列相同类型的数据。
2.1.7数组的长度
在Java中,数组的长度是指数组中元素的数量。数组的长度是在创建数组时确定的,并且在整个程序执行期间保持不变。要获取数组的长度,可以使用数组对象的 length 属性。
1、length 属性
Java数组对象具有一个名为 length 的属性,它表示数组的长度。例如,对于一个整数数组 int[] numbers = new int[5];,可以通过 numbers.length 来获取数组的长度。
2、固定长度
Java数组的长度在创建时确定,并且无法在运行时改变。数组一旦创建,其长度将保持不变。
3、数组索引从0开始
Java数组的索引从0开始,因此有效的索引范围是从0到 length - 1。
数组的长度可以用于控制循环的次数,特别是在使用 for 循环遍历数组时,可以利用数组的长度来设置循环的结束条件,遍历每个元素。
下面是一个示例,展示了如何使用数组的 length 属性获取数组长度:
int[] numbers = {10, 20, 30, 40, 50};
int length = numbers.length;
System.out.println("数组长度: " + length);
在上述示例中,我们创建了一个整数数组 numbers,包含5个元素。通过 numbers.length 获取数组的长度,并将其赋值给 length 变量。最后,我们打印输出数组的长度。
通过使用数组的 length 属性,我们可以轻松地获取数组的长度,进而进行相应的操作和控制,例如遍历数组、验证数组的有效性等。
2.1.8【案例】for循环遍历数组元素
数组的好处在于批量管理数据,它方便了对数据进行批量处理,例如执行各种统计、计算、打印或其他操作。而常见的批量处理数组元素操作就是遍历数组。遍历数组是指对每个元素执行相应的操作或获取其值的过程。
数组的下标是从0开始的序号,直到 length-1 结束。这个特性使得使用 for 循环来迭代数组的每个元素非常合适。for 循环提供了一种简洁而方便的方式来遍历数组,并在每次循环中访问数组的一个元素。
以下是使用 for 循环来遍历数组元素的示例:
int[] arr = {8, 10, 5, 3, 12};
int sum = 0;
// 遍历数组
for (int i = 0; i < arr.length; i++) {sum += arr[i];
}
System.out.println(sum);
在上述示例中,我们创建了一个整数数组 arr,并使用 for 循环遍历数组的每个元素。
循环的初始化部分 int i = 0 将变量 i 初始化为 0,表示从数组的第一个元素开始遍历。条件部分 i < arr.length 表示只要 i 小于数组的长度,就继续循环。递增部分 i++ 在每次循环结束后将 i 增加 1。
循环体内,我们使用索引 i 来访问数组的元素,并将其累加到变量 sum 中。然后,我们将 sum 打印输出。
通过使用 for 循环遍历数组元素,我们可以逐个访问数组中的元素,并执行相应的操作。这种方式简洁而直观,并且适用于大多数数组遍历的场景。
2.2 二维数组
2.2.1 什么是二维数组
在Java中,二维数组是指由多个一维数组组成的数组。它可以被看作是一个表格或矩阵,其中每个元素都有两个索引来定位,即行索引和列索引。
二维数组在Java中的声明和初始化可以使用以下语法:
dataType[][] arrayName = new dataType[rowSize][columnSize];
其中:
- dataType 表示数据类型
- arrayName 是二维数组的名称
- rowSize 表示行的数量
- columnSize 表示列的数量
以下是一个示例,展示了如何声明、初始化和访问二维数组的元素:
int[][] matrix = new int[3][4];
matrix[0][0] = 1;
matrix[0][1] = 2;
matrix[0][2] = 3;
matrix[0][3] = 4;
matrix[1][0] = 5;
matrix[1][1] = 6;
matrix[1][2] = 7;
matrix[1][3] = 8;
matrix[2][0] = 9;
matrix[2][1] = 10;
matrix[2][2] = 11;
matrix[2][3] = 12;
在上述示例中,我们创建了一个名为 matrix 的二维整数数组,它有3行和4列。然后,我们使用索引来访问并赋值数组的各个元素。
通过指定行索引和列索引,我们可以访问和操作二维数组中的特定元素。例如,matrix[0][0] 表示第一行第一列的元素,其值为1。
二维数组在许多应用中非常有用,例如存储矩阵数据、表示游戏棋盘、处理图像等。它提供了一种方便的方式来组织和操作多维数据。
2.2.2【案例】遍历二维数组
二维数组可以通过嵌套的 for 循环来遍历和访问所有元素。下面是一个示例:
int[][] matrix = {{1, 2, 3},{4, 5, 6},{7, 8, 9}
};
// 遍历二维数组并打印输出
for (int i = 0; i < matrix.length; i++) {for (int j = 0; j < matrix[i].length; j++) {System.out.print(matrix[i][j] + " ");}System.out.println();
}
在上述示例中,我们创建了一个名为 matrix 的二维整数数组,并初始化了其中的元素。该二维数组有3行和3列。
我们使用嵌套的 for 循环来遍历二维数组的所有元素。外层的循环控制行的遍历,内层的循环控制列的遍历。通过索引 i 和 j 访问二维数组中的元素,并使用 System.out.print() 方法打印输出每个元素。
在内层循环结束后,我们使用 System.out.println() 方法换行,以便在每行输出完毕后进行换行。
通过使用嵌套的 for 循环,我们可以遍历并访问二维数组中的每个元素,并执行相应的操作。这种方式非常适用于需要处理二维数据的场景,如矩阵运算、图像处理等。