流程控制【代码块与作用域】【选择结构】【循环结构】
@
源码:
Gitee https://gitee.com/drip123456/java-se
GIthub https://github.com/Drip123456/JavaSE
专栏: JavaSE笔记专栏
代码块与作用域
在开始流程控制语句之前,我们先来介绍一下代码块和作用域。
不知道各位小伙伴是否在一开始就注意到了,为什么程序中会有一些成对出现的花括号?这些花括号代表什么意思呢?
public class Main { //外层花括号
public static void main(String[] args) { //内层花括号开始
} //内层花括号结束
}
我们可以在花括号中编写一句又一句的代码,实际上这些被大括号囊括起来的内容,我们就称为块(代码块),一个代码块中可以包含多行代码,我们可以在里面做各种各样的事情,比如定义变量、进行计算等等。
我们可以自由地创建代码块:
public static void main(String[] args) { //现目前这个阶段,我们还是在主方法中编写代码,不要跑去外面写
System.out.println("外层");
{ //自由创建代码块
int a = 10;
System.out.println(a);
}
}
虽然创建了代码块,但实际上程序依然是按照从上到下的顺序在进行的,所以说这里还是在逐行运行,即使使用花括号囊括。那咋一看这不就是没什么卵用吗?我们来看看变量。
我们创建的变量,实际上是有作用域的,并不是在任何地方都可以使用,比如:
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
变量的使用范围,仅限于其定义时所处的代码块,一旦超出对应的代码块区域,那么就相当于没有这个变量了。
public static void main(String[] args) {
int a = 10; //此时变量在最外层定义
{
System.out.println(a); //处于其作用域内部的代码块可以使用
}
System.out.println(a); //这里肯定也可以使用
}
我们目前所创建的变量都是局部变量(有范围限制),后面我们会介绍更多种类型的变量,了解了代码块及作用域之后,我们就可以正式开启流程控制语句的学习了。
选择结构
某些时候,我们希望进行判断,只有在条件为真时,才执行某些代码,这种情况就需要使用到选择分支语句,首先我们来认识一下if
语句:
if (条件判断) 判断成功执行的代码;
public static void main(String[] args) {
int a = 15;
if(a == 15) //只有当a判断等于15时,才会执行下面的打印语句
System.out.println("Hello World!");
System.out.println("我是外层"); //if只会对紧跟着的一行代码生效,后续的内容无效
}
if
会进行判断,只有判断成功时才会执行紧跟着的语句,否则会直接跳过,注意,如果我们想要在if中执行多行代码,需要使用代码块将这些代码囊括起来(实际上代码块就是将多条语句复合到一起)所以说,我们以后使用if时,如果分支中有多行代码需要执行,就需要添加花括号,如果只有一行代码,花括号可以直接省略,包括我们后面会讲到的else、while、for语句都是这样的。
public static void main(String[] args) {
int a = 15;
if(a > 10) { //只有判断成功时,才会执行下面的代码块中内容,否则直接跳过
System.out.println("a大于10");
System.out.println("a的值为:"+a);
}
System.out.println("我是外层");
}
如果我们希望判断条件为真时执行某些代码,条件为假时执行另一些代码,我们可以在后面继续添加else语句:
public static void main(String[] args) {
int a = 15;
if(a > 10) { //只有判断成功时,才会执行下面的代码块中内容,否则直接跳过
System.out.println("a大于10");
System.out.println("a的值为:"+a);
} else { //当判断不成功时,会执行else代码块中的代码
System.out.println("a小于10");
System.out.println("a的值为:"+a);
}
System.out.println("我是外层");
}
if-else
语句就像两个分支,跟据不同的判断情况从而决定下一步该做什么,这跟我们之前认识的三元运算符性质比较类似。
那如果此时我们需要判断多个分支呢?比如我们现在希望判断学生的成绩,不同分数段打印的等级不一样,比如90以上就是优秀,70以上就是良好,60以上是及格,其他的都是不及格,那么这种我们又该如何判断呢?要像这样进行连续判断,我们需要使用else-if
来完成:
public static void main(String[] args) {
int score = 2;
if(score >= 90) //90分以上才是优秀
System.out.println("优秀");
else if (score >= 70) //当上一级if判断失败时,会继续判断这一级
System.out.println("良好");
else if (score >= 60)
System.out.println("及格");
else //当之前所有的if都判断失败时,才会进入到最后的else语句中
System.out.println("不及格");
}
当然,if
分支语句还支持嵌套使用,比如我们现在希望低于60分的同学需要补习,0-30分需要补Java,30-60分需要补C++,这时我们就需要用到嵌套:
public static void main(String[] args) {
int score = 2;
if(score < 60) { //先判断不及格
if(score > 30) //在内层再嵌套一个if语句进行进一步的判断
System.out.println("学习C++");
else
System.out.println("学习Java");
}
}
除了if自己可以进行嵌套使用之外,其他流程控制语句同样可以嵌套使用,也可以与其他流程控制语句混合嵌套使用。这样,我们就可以灵活地使用if
来进行各种条件判断了。
前面我们介绍了if语句,我们可以通过一个if语句轻松地进行条件判断,然后根据对应的条件,来执行不同的逻辑,当然除了这种方式之外,我们也可以使用switch
语句来实现,它更适用于多分支的情况:
switch (目标) { //我们需要传入一个目标,比如变量,或是计算表达式等
case 匹配值: //如果目标的值等于我们这里给定的匹配值,那么就执行case后面的代码
代码...
break; //代码执行结束后需要使用break来结束,否则会溜到下一个case继续执行代码
}
比如现在我们要根据学生的等级进行分班,学生有ABC三个等级:
public static void main(String[] args) {
char c = 'A';
switch (c) { //这里目标就是变量c
case 'A': //分别指定ABC三个匹配值,并且执行不同的代码
System.out.println("去尖子班!准备冲刺985大学!");
break; //执行完之后一定记得break,否则会继续向下执行下一个case中的代码
case 'B':
System.out.println("去平行班!准备冲刺一本!");
break;
case 'C':
System.out.println("去职高深造。");
break;
}
}
switch
可以精准匹配某个值,但是它不能进行范围判断,比如我们要判断分数段,这时用switch就很鸡肋了。
当然除了精准匹配之外,其他的情况我们可以用default来表示:
switch (目标) {
case: ...
default:
其他情况下执行的代码
}
我们还是以刚才那个例子为例:
public static void main(String[] args) {
char c = 'A';
switch (c) {
case 'A':
System.out.println("去尖子班!");
break;
case 'B':
System.out.println("去平行班!");
break;
case 'C':
System.out.println("去差生班!");
break;
default: //其他情况一律就是下面的代码了
System.out.println("去读职高,分流");
}
}
当然switch中可以继续嵌套其他的流程控制语句,比如if:
public static void main(String[] args) {
char c = 'A';
switch (c) {
case 'A':
if(c == 'A') { //嵌套一个if语句
System.out.println("去尖子班!");
}
break;
case 'B':
System.out.println("去平行班!");
break;
}
}
目前,我们已经认识了两种选择分支结构语句。
循环结构
通过前面的学习,我们了解了如何使用分支语句来根据不同的条件执行不同的代码,我们接着来看第二种重要的流程控制语句:循环语句。
我们在某些时候,可能需要批量执行某些代码:
public static void main(String[] args) {
System.out.println("伞兵一号卢本伟准备就绪!"); //把这句话给我打印三遍
System.out.println("伞兵一号卢本伟准备就绪!");
System.out.println("伞兵一号卢本伟准备就绪!");
}
遇到这种情况,我们由于还没学习循环语句,那么就只能写N次来实现这样的多次执行。但是如果此时要求我们将一句话打印100遍、1000遍、10000遍,那么我们岂不是光CV代码就要搞一下午?
现在,要解决这种问题,我们可以使用for循环语句来多次执行:
for (表达式1;表达式2;表达式3) 循环体;
介绍一下详细规则:
- 表达式1:在循环开始时仅执行一次。
- 表达式2:每次循环开始前会执行一次,要求为判断语句,用于判断是否可以结束循环,若结果为真,那么继续循环,否则结束循环。
- 表达式3:每次循环完成后会执行一次。
- 循环体:每次循环都会执行一次循环体。
一个标准的for循环语句写法如下:
public static void main(String[] args) {
//比如我们希望让刚刚的打印执行3次
for (int i = 0; i < 3; i++) //这里我们在for语句中定义一个变量i,然后每一轮i都会自增,直到变成3为止
System.out.println("伞兵一号卢本伟准备就绪!"); //这样,就会执行三轮循环,每轮循环都会执行紧跟着的这一句打印
}
我们可以使用调试来观察每一轮的变化,调试模式跟普通的运行一样,也会执行我们的Java程序,但是我们可以添加断点,也就是说当代码运行到断点位置时,会在这里暂停,我们可以观察当代码执行到这个位置时各个变量的值:
调试模式在我们后面的学习中非常重要,影响深远,所以说各位小伙伴一定要学会。调试也很简单,我们只需要点击右上角的调试选项即可(图标像一个小虫子一样,因为调试的英文名称是Debug)
调试开始时,我们可以看到程序在断点位置暂停了:
此时我们可以观察到当前的局部变量i
的值,也可以直接在下方的调试窗口中查看:
随着循环的进行,i的值也会逐渐自增:
当i
增长到2时,此时来到最后一轮循环,再继续向下运行,就不再满足循环条件了,所以说此时就会结束循环。
当然,如果要执行多条语句的话,只需要使用花括号囊括就行了:
for (int i = 0; i < 3; i++) {
System.out.println("伞兵一号卢本伟准备就绪!");
System.out.println("当前i的值为:"+i);
}
注意这里的i
仅仅是for循环语句中创建的变量,所以说其作用域被限制在了循环体中,一旦离开循环体,那么就无法使用了
但是我们可以将i
的创建放到外面:
public static void main(String[] args) {
int i = 0; //在外面创建变量i,这样全部范围内都可以使用了
for (; i < 3; i++) { //for循环的三个表达式并不一定需要编写
System.out.println("伞兵一号卢本伟准备就绪!");
System.out.println("当前i的值为:"+i);
}
System.out.println("当前i的值为:"+i);
}
和之前的if
一样,for循环同样支持嵌套使用:
public static void main(String[] args) {
for (int i = 0; i < 3; i++) //外层循环执行3次
for (int j = 0; j < 3; j++) //内层循环也执行3次
System.out.println("1!5!");
}
上面的代码中,外层循环会执行3轮,而整个循环体又是一个循环语句,那么也就是说,每一轮循环都会执行里面的整个循环,里面的整个循环会执行3,那么总共就会执行3 x 3次,也就是9次打印语句。
实际上,for循环的三个表达式并不一定需要编写,我们甚至可以三个都不写:
public static void main(String[] args) {
for (;;) //如果什么都不写,相当于没有结束条件,这将会导致无限循环
System.out.println("伞兵一号卢本伟准备就绪!");
}
如果没有表达式2,那么整个for循环就没有结束条件,默认会判定为真,此时就会出现无限循环的情况(无限循环是很危险的,因为它会疯狂地消耗CPU资源来执行循环,可能很快你的CPU就满载了,一定要避免)
当然,我们也可以在循环过程中提前终止或是加速循环的进行,这里我们需要认识两个新的关键字:
public static void main(String[] args) {
for (int i = 0; i < 3; i++) {
if(i == 1) continue; //比如我们希望当i等于1时跳过这一轮,不执行后面的打印
System.out.println("伞兵一号卢本伟准备就绪!");
System.out.println("当前i的值为:"+i);
}
}
我们可以使用continue
关键字来跳过本轮循环,直接开启下一轮。这里的跳过是指,循环体中,无论后面有没有未执行的代码,一律不执行,比如上面的判断如果成功,那么将执行continue
进行跳过,虽然后面还有打印语句,但是不会再去执行了,而是直接结束当前循环,开启下一轮。
在某些情况下,我们可能希望提前结束循环:
for (int i = 0; i < 3; i++) {
if(i == 1) break; //我们希望当i等于1时提前结束
System.out.println("伞兵一号卢本伟准备就绪!");
System.out.println("当前i的值为:"+i);
}
我们可以使用break
关键字来提前终止整个循环,和上面一样,本轮循环中无论后续还有没有未执行的代码,都不会执行了,而是直接结束整个循环,跳出到循环外部。
虽然使用break和continue关键字能够更方便的控制循环,但是注意在多重循环嵌套下,它只对离它最近的循环生效(就近原则):
for (int i = 1; i < 4; ++i) {
for (int j = 1; j < 4; ++j) {
if(i == j) continue; //当i == j时加速循环
System.out.println(i+", "+j);
}
}
这里的continue
加速的对象并不是外层的for,而是离它最近的内层for循环,break
也是同样的规则:
for (int i = 1; i < 4; ++i) {
for (int j = 1; j < 4; ++j) {
if(i == j) break; //当i == j时终止循环
System.out.println(i+", "+j);
}
}
那么,要是我们就是想要终止或者是加速外层循环呢?我们可以为循环语句打上标记:
outer: for (int i = 1; i < 4; ++i) { //在循环语句前,添加 标签: 来进行标记
inner: for (int j = 1; j < 4; ++j) {
if(i == j) break outer; //break后紧跟要结束的循环标记,当i == j时终止外层循环
System.out.println(i+", "+j);
}
}
如果一个代码块中存在多个循环,那么直接对当前代码块的标记执行break
时会直接跳出整个代码块:
outer: { //直接对整个代码块打标签
for (int i = 0; i < 10; i++) {
if (i == 7){
System.out.println("Test");
break outer; //执行break时,会直接跳出整个代码块,而不是第一个循环
}
}
System.out.println("???");
}
虽然效果挺奇特的,但是一般情况下没人这么玩,所以说了解就行了。
前面我们介绍了for循环语句,我们接着来看第二种while循环,for循环要求我们填写三个表达式,而while相当于是一个简化版本,它只需要我们填写循环的维持条件即可,比如:
while(循环条件) 循环体;
相比for循环,while循环更多的用在不明确具体的结束时机的情况下,而for循环更多用于明确知道循环的情况,比如我们现在明确要进行循环10次,此时用for循环会更加合适一些,又比如我们现在只知道当i
大于10时需要结束循环,但是i
在循环多少次之后才不满足循环条件我们并不知道,此时使用while就比较合适了。
public static void main(String[] args) {
int i = 100; //比如现在我们想看看i不断除以2得到的结果会是什么,但是循环次数我们并不明确
while (i > 0) { //现在唯一知道的是循环条件,只要大于0那么就可以继续除
System.out.println(i);
i /= 2; //每次循环都除以2
}
}
上面的这种情况就非常适合使用while循环。
和for循环一样,while也支持使用break和continue来进行循环的控制,以及嵌套使用:
public static void main(String[] args) {
int i = 100;
while (i > 0) {
if(i < 10) break;
System.out.println(i);
i /= 2;
}
}
我们也可以反转循环判断的时机,可以先执行循环内容,然后再做循环条件判断,这里要用到do-while
语句:
public static void main(String[] args) {
int i = 0; //比如现在我们想看看i不断除以2得到的结果会是什么,但是循环次数我们并不明确
do { //无论满不满足循环条件,先执行循环体里面的内容
System.out.println("Hello World!");
i++;
} while (i < 10); //再做判断,如果判断成功,开启下一轮循环,否则结束
}
至此,面向过程相关的内容就讲解完毕了,从下一章开始,我们将进入面向对象编程的学习(类、数组、字符串)