【JAVA进化论】LV1-4:条件语句&循环语句

通过前面的介绍,我们已经了解了变量运算符,通过运算符可以将多个变量进行不同的运算,这已经可以做出一个计算器了,可是一段具备各种逻辑的程序,仅靠简单的运算是无法完成的,于是,我们便有了各种条件语句循环语句,用来组合运算逻辑,从而实现更为复杂的业务逻辑。

一、条件语句

1.1:if、else if、else

先来看一个例子:

代码块1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public static void main(String[] args) {

int a = 1;

if (a == 1) {

//这里放a等于1时的逻辑代码

} else if (a == 2) {

//这里放a等于2时的逻辑代码

} else if (a == 3) {

//这里放a等于3的逻辑代码

} else {

//如果a不满足上面任意一个条件,则走这里的逻辑

}
}

这就是if条件语句的基本用法,它一定是以if开头的,如果除了if头的条件不满足,还需要别的判断条件,则使用else if,如果没有任何满足的条件时需要做进一步处理,则使用else,条件语句括号内的语句,一定是一个关系运算式,结果为truefalse,结果为true,则走对应的代码块,它的运行模式如下:

图1

由图知:if语句从上到下开始判断,一旦碰到条件满足的,就执行满足条件的代码块,其余代码块不再运行,思考,下方哪个代码块会执行?

代码块2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void main(String[] args) {

int a = 3;

if (a == 1) {
//代码块1
} else if (a == 2 || a == 3) {
//代码块2
} else if (a == 3) {
//代码块3
} else {
//代码块4
}
}

首先,第二个条件语句(a == 2 || a == 3)和(a == 3)都是true,那么究竟是执行代码块2还是执行代码块3呢?答案是代码块2,因为上面已经说过了,判断时只要遇到一个true,就直接执行对应的代码块了,其余的代码块都不会生效。

ok,看完上面的案例,再来说下if语句本身,if语句的else或者else if是可以不存在的,比如我现在仅做一个最基本的判断:

代码块3
1
2
3
4
5
6
7
int a = 3;

if (a == 1) {
//代码块1
}

//其它代码

这段代码的意思是说,只要a的值为1,就会执行代码块1,其它不需要做任何判断,同样的,if可以跟一个else使用:

代码块4
1
2
3
4
5
6
7
8
9
int a = 3;

if (a == 1) {
//代码块1
} else {
//代码块2
}

//其它代码

这段代码的意思是说,如果a的值为1,则运行代码块1,如果a的值不等于1,则运行代码块2.

if也可以单独跟一个或多个else if一块使用:

代码块5
1
2
3
4
5
6
7
8
9
int a = 3;

if (a == 1) {
//代码块1
} else if(a == 2) {
//代码块2
}

//其它代码

这段代码的意思是说,如果a的值为1,则运行代码块1,如果a的值为2,则运行代码块2。

1.2:switch、case

语法如下:

代码块6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static void main(String[] args) {

int a = 2;

switch (a){
case 1:
//代码块1
break;
case 2:
//代码块2
break;
case 3:
//代码块3
break;
default:
//代码块4
}
}

语法规范:switch括号内的类型只能是基本类型、枚举类、String,一个switch里可以包含多个case,default可以写也可以不写。

它是用来做什么的呢?

其实它有些像if语句,用来匹配符合规则的代码块,以代码块6为例,它的执行流程如下:

图2

可以看到,switch也是自上到下根据条件判断出需要执行的代码块,那么这个break又是什么意思呢?根据图2可以发现它是用来终止程序用的,如果少了break会发生什么?如下图,现在我们把程序里的break去掉:

图3

可以看到,如果在case2的代码里没有做程序终止,则从case2开始往下的每一项都会触发执行。

那么,default这一项是干嘛的?这个其实跟if里的else类似,就是switch内的值在case内没有任何匹配项的时候,默认触发的代码块,此外switch是允许不定义此项的。

ok,了解了switch的执行流程,那么请思考一下下方这个结果应该输出多少?

代码块7
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int a = 2;

switch (a){
case 1:
System.out.println(1);
break;
case 2:
System.out.println(2);
case 3:
System.out.println(3);
break;
default:
System.out.println("default");
}

答案:输出2和3

那么下面这个输出什么呢?

代码块8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int a = 233; //注意这里a的值变了

switch (a){
case 1:
System.out.println(1);
break;
case 2:
System.out.println(2);
break;
case 3:
System.out.println(3);
break;
default:
System.out.println("default");
}

答案:default

二、循环语句

2.1:for循环语句

语法如下:

代码块9
1
2
3
4
5
6
7
public static void main(String[] args) {

for (int i = 0; i < 10; i++) {
System.out.println(i + "哔哩哔哩干杯");
}

}

上面这个程序会输出10个字符串,即:0哔哩哔哩干杯 ~ 9哔哩哔哩干杯,for循环是如何运行的?它是以什么为依据运行10遍的?下面我们来拆解下它的语法:

图4

图4,根据对括号内的了解,我们来梳理下代码块9里的执行过程:

图5

请仔细阅读图5中的流程,这是推动for循环执行的流程。

学完了if语句和for循环,我们来写一个程序,程序要求:输出0~9里的奇数和偶数,最后将它们按照空格分开打印出来:

代码块10
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static void main(String[] args) {

String odd = ""; //声明存放奇数数据的字符串
String even = ""; //声明存放偶数数据的字符串

for (int i = 0; i < 10; i++) { //循环运行,每次i+1,一共循环10次,i的赋值范围为0~9
if (i % 2 == 0) {
even += i + " "; //如果被2整除,则说明是偶数,加空格后拼在even后面
} else {
odd += i + " "; //如果不能被2整除,则说明是奇数,加空格后拼在odd后面
}
}

System.out.println("0~9中的奇数为:" + odd);
System.out.println("0~9中的偶数为:" + even);

}

输出结果为:

代码块11
1
2
0~9中的奇数为:1 3 5 7 9
0~9中的偶数为:0 2 4 6 8

2.2:while、do while

while循环的语法如下:

代码块12
1
2
3
4
5
6
7
8
9
public static void main(String[] args) {

int i=0;

while (i<10){
System.out.println(i + "哔哩哔哩干杯");
i++;
}
}

这个跟代码块9输出一样,也是:0哔哩哔哩干杯 ~ 9哔哩哔哩干杯,先来说下while这个单词本身的意思,它的意思是“当….的时候”,所以while(i<10)这句话就很好理解了,就是当i的值小于10的时候,运行while循环体里的代码,相比for循环,while理解起来相对简单,它的运行流程图不再画。

do while跟while类似,将代码块12里的代码利用do while改造一下:

代码块13
1
2
3
4
5
6
7
8
9
10
public static void main(String[] args) {

int i = 0;

do {
System.out.println(i + "哔哩哔哩干杯");
i++;
} while (i < 10);

}

输出结果跟while一致,那你可能要问了,while和do while有啥区别?

来看下它们的执行流程图:

图6

这就是它们的区别,while上去就会判断条件是否满足,从而决定是否走下去,而do while往往上去就会触发一次循环体,然后才做判断决定是否再次触发循环体。

按照代码块13的逻辑来说,while和do while确实没差别,因为i一开始确实小于10,所以第一次的时候无论如何都会触发一次循环体里的逻辑,是否先判断条件已经无所谓了,我们来举一个不一样的例子:

代码块14
1
2
3
4
5
6
7
8
9
10
public static void main(String[] args) {

int i = 10;

do {
i--;
System.out.println(i + "哔哩哔哩干杯");
} while (i > 0 && i < 10);

}

这段代码输出为:9哔哩哔哩干杯 ~ 0哔哩哔哩干杯

我们现在用while改造一下:

代码块15
1
2
3
4
5
6
7
8
9
10
public static void main(String[] args) {

int i = 10;

while (i > 0 && i < 10) {
i--;
System.out.println(i + "哔哩哔哩干杯");
}

}

这段代码啥也不会输出,因为while会先判断循环条件是否成立,再决定走不走循环体,而需要i<10成立的i–操作却在循环体内,因此代码块14成功执行,而代码块15未成功。

三、数组&for增强

3.1:数组是什么?

我们前面讲基本类型变量时说过,设置一个变量的步骤是:①声明、②赋值、③使用,但是当时的变量都是我们一个个声明的,有没有一种方式可以一次性声明n个变量呢?数组就是这样一种结构,它允许一次性声明n个变量,并且支持逐个赋值,数组跟基本类型一样,也需要声明,声明方式为:

代码块16
1
2
int[] nums = new int[10]; //这种声明方式只是简单的定义了一个容量为10的int型数组,并未给内部的元素赋值
int[] nums2 = {1, 222, 334, 566, 256}; //这种声明方式就是连带着初始值给每个元素都赋上了,这里是指从0~5的下标的元素值分别为:1, 222, 334, 566, 256

上述的代码的第一段就是声明了一个同时声明了10个int型变量的数组变量(套娃中…),也是常用的数组声明方式,那么之前也说过了,java除了基本变量之外,其余全都是引用变量,因此,数组类型也是一种引用变量,引用变量的原理性质的东西到讲类的时候会细说。

数组到底是什么?代码块16那样的做法会发生什么?

先说下数组的结构,数组就是包含了多个元素的集合,例如代码中的nums,本身就一次性声明了10个int型元素,那么我们知道int型如果不给赋值的话,它的默认值是0,如何给数组里的元素赋值呢?这里就要引出一个叫做下标的东西,下标的含义就是指元素本身在数组中的位置,下标从0开始计算,nums在完成声明后的结构如下:

图7

那么现在我如果要给下标5的数赋值为256,该如何操作呢?看代码:

代码块17
1
nums[5] = 256;

利用数组变量,将下标值放进去,即认为操作的就是对应元素本身,因此利用等号赋值即可,赋完值的nums如下:

图8

下标为5的int型数据元素已经被成功赋值了。

那么如何批量赋值呢?这样一个个的赋值太麻烦了,如果现在有一个size为10000的数组,这样一个个赋值会死人的~还记得本节所学的内容吗?循环啊,就不能利用循环赋值吗?比如for循环,完全可以把循环体里的i变量当成下标访问数组里的元素哇,现在我们利用循环操作,来给nums这个数组的每个元素都赋上256:

代码块18
1
2
3
4
5
6
7
8
public static void main(String[] args) {

int[] nums = new int[10];

for (int i = 0; i < 10; i++) {
nums[i] = 256; //利用i当做nums的下标来访问它里面的元素
}
}

这样nums里面的每一个元素的值就都是256了~

再思考一个问题,这里因为我们事先知道了nums的元素个数是10个,下标是0~9,所以for循环里的i初始化为0,每次自增1,且自增至9终止循环,正好把nums里的每个元素赋值一遍,那如果我们事先不知道数组大小该怎么办?这时可以利用数组变量自带的方法length来获取数组的大小:

代码块19
1
2
3
for (int i = 0; i < nums.length; i++) { //nums.length返回的就是数组大小,本例中就是10
nums[i] = 256;
}

我们现在知道了根据数组的下标可以访问数组内具体的元素,通过循环体可以按照循环自增的i值快速访问整个数组(这个过程叫做“遍历”),那么现在我想要输出整个数组里每一个元素的值就变得很简单了,依然是for循环:

代码块20
1
2
3
for (int i = 0; i < nums.length; i++) {
System.out.println(nums[i]); //仍然是i当下标,将对应的数值输出即可
}

3.2:for增强

遍历数组其实除了上述的方式之外,还有一种增强方式,写法如下:

代码块21
1
2
3
for (int num : nums) {
System.out.println(num);
}

可以看到,for增强连下标都省去了,直接使用数组的基本类型接收都行,它是用来简化数组遍历的一种方式。

3.3:二维数组&for嵌套

上面介绍了数组,数组就是简单一批数据,那么二维数组又是啥?

相比一维数组,二维数组跟它的名字一样,具有横竖两个维度的元素,它的结构如下:

图9

可见,相比一维数组,二维数组定位到一个元素需要两个下标,那么给二维数组里的每一个元素赋值就不能用一个for循环来进行了,这时需要借助我们的for嵌套:

代码块22
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public static void main(String[] args) {
int[][] a = new int[5][5];

//获取横向的长度
int lenX = a.length;
//获取纵向的长度
int lenY = a[0].length;

for (int i = 0; i < lenX; i++) {
for (int j = 0; j < lenY; j++) {
a[i][j] = 1;
}
}

//遍历与打印
for (int i = 0; i < lenX; i++) {
for (int j = 0; j < lenY; j++) {
System.out.print(a[i][j]);
}
//每遍历完一遍横轴的元素,则换一次行
System.out.println();
}
}

❓ 思考:请仔细阅读上面的代码,根据自己学过的for循环,想象一下for嵌套的执行顺序。