Java继承了C语言的所有控制语句,并在C语言的基础加以扩展形成了自己的控制流语句。Java语言的控制流分为:
分支:if-else、switch
循环:while、do-while、for
流程控制:break、continue
-
true 和 false
所有的条件语句都是利用条件表达式来决定执行的路径。表达式返回布尔值true或者false,Java不允许使用数字作为布尔值使用。
-
分支
分支语句代表着选择,就像走到岔路口,向左还是向右,正确的选择能够决定你是否能够正确高效的到达目的地。对于向左向右类的问题,我们使用if-else语句来表示:
非此即彼:if-else
基本if-else
此处我们借用莎翁在《哈姆雷特》中的名句体现:
if(to be){
System.out.println("Take arms against a sea of troubles,And by opposing end them");;
} else{
System.out.println("Suffer the slings and arrows of outrageous fortune");
}
我们可以发现,这个分支控制由三个部分组成:
条件语句:生存还是毁灭?(to be or not to be)
if语句:毁灭(to be)=> 挺身反抗人世的无涯的苦难, 在奋斗中扫清那一切
else语句:生存(not to be)=> 默然忍受命运的暴虐的毒箭
他们的语义如下:如果符合条件判断,执行if语句,否则执行else语句
其中,else语句有时候可以省略,比如如下场景,如果明天下雨那么我就要带伞出门。
if(rain){
// brain a umbrella
}
其实这句话隐含了一个条件,如果明天不下雨,那么我什么也不会带。即当else条件为不做任何事的时候,我们可以省略else语句。
使用return简化if-else
还有一种情况在方法中,一旦执行 return 语句,那么会直接退出方法,并返回结果,后续的所有语句都不会被执行,因此我们可以使用return 简化分支语句。例如前面的例子,我们可以改写为:
if(to be){
System.out.println("Take arms against a sea of troubles,And by opposing end them");
return;
}
System.out.println("Suffer the slings and arrows of outrageous fortune");
当条件符合时,进入if语句,执行输出,然后直接退出方法,不再执行line5。或者条件不符合,跳过if语句,执行line5。
连续判断:if-else if
基本if-else if
当然,实际使用中,往往是多重分支题ABCD….此时简单的if-else就不在能解决问题了,因此我们引入:
我们来做一道选择题:
1+1=?
A.1, B.2, C.3
那么如何判断选择哪个选项呢?最小有效的方式应该是先计算出答案,然后依次对比每个选项,看哪个是正确的:
int result = 1+1;
if(result == 1){
System.out.println("A");
}else{
if(result == 2){
System.out.println("B");
} else {
System.out.println("C");
}
}
// 输出
B
判断1+1=1?返回A,否则再判断1+1=2?返回B,否则就返回C。你是否可以感受到,这种写法难以阅读,难以理解,每多一个选项就要加一层判断,一层又一层,三层,四层,五层?请观察六个分支的代码:
int result = 1+1;
if (result == 1){
System.out.println("A");
}else {
if (result==2) {
System.out.println("B");
}else{
if (result==3) {
System.out.println("C");
}else {
if (result==4) {
System.out.println("D");
}else {
if(result == 5){
System.out.println("E");
}else {
if (result == 6){
System.out.println("F");
}
}
}
}
}
}
// 输出
B
显然这种写法可以实现需求,但是多层的代码快和缩进非常复杂且臃肿,因此Java中引入了if-else if语句。我们使用if-else if语句来改造上述代码:
int result = 1+1;
if(result == 1){
System.out.println("A");
}else if(result == 2){
System.out.println("B");
}else{
System.out.println("C");
}
// 输出
B
把多层的缩进压缩成同一层,减少了多层的缩进,这样代码阅读起来,连续且清晰。
使用return简化
还记得,上一节中使用return简化的方法吗?我们是否可以也使用同样的方式呢?
当然,它同样适用:
int result = 1+1;
if(result == 1){
System.out.println("A");
return;
}
if(result == 2){
System.out.println("B");
return;
}
System.out.println("C");
// 输出
B
我们看到这种写法相对于if-else if来说,更加简洁。但是你发现,我们在不断地重复写result == a,result == b,result==xx …我们在对同一个变量做不同的对比,这无疑有些繁琐。我们是否能够将这部分也简化呢?
请允许我像你介绍:switch分支语句。
多重分支:switch
基本switch:
针对同一个变量,的连续判断,我们可以使用switch语句。switch可以使用基本类型和字符串来作为分支选择器。
以上面选择题为例吗,我们使用switch语句来实现:
int result = 1+1;
switch (result){
case 1:
System.out.println("A");
break;
case 2:
System.out.println("B");
break;
case 3:
System.out.println("C");
break;
case 4:
System.out.println("D");
}
// 输出
B
注意此处的break,是必须要写的,他代表结束本次判断。switch的逻辑是,依次对比case,直到找到符与判断值相同的值,然后依次执行后面的所有语句,会将符合条件的B后面的C,D也同样输出,这显然不是我们期望的,因此在执行完相应的语句后,我们使用break结束判断,从而避免输出后续不想要的答案。
default
显然switch有效的简化了多分支条件的判断,那么让我们用它再做一道题吧:
2*3=?
A.1, B.2, C.3
使用上面的方法写出程序后你会发现没有任何输出,因为计算机已经陷入迷惑。因为这题目就出错了,没有正确答案!没错,编程过程中有时候会出现你意料之外的分支,那么我们的switch语句难道就不能使用了吗?No,有请不存在再选项中的答案出场。
int result = 2*3;
switch (result){
case 1:
System.out.println("A");
break;
case 2:
System.out.println("B");
break;
case 3:
System.out.println("C");
break;
default :
System.out.println("Wrong question!");
}
// 输出
Wrong question!
执行之后,你发现计算机不再迷惑,向你抗议到Wrong question!
-
循环
当我们编程过程中发现有需要不断重复相同的操作时,我们就要使用到循环。循环就像轮回,一次一次,相同的事情发生,周而复始,直到一件特定的事件发生打破循环。编程中的循环也是,它应该具有两个最基本的元素:
不断发生的相同的事件=>循环体
打破循环的特殊事件 => 退出/进入条件
二者缺一不可,如果缺少了循环体,那么循环就是原地打转不执行任何有意义的步骤,会使程序一直停留在这里,不向下执行,没有意义(当然,在一些实际编程中,我们可以故意使用空循环来达到一定的目的,比如认为的制造延迟等待)。而如果缺少退出条件,程序就会被困在循环中如,果没有外力干预,将会不断重复执行,永无休止,而这种循环编程中我们成为“死循环”,意味着程序会卡死在这里,。(编程中,我们应该避免死循环的出现,但是在一些特殊的程序中,死循环也可以作为一种手段处理一些特定的需求)。
java 中关于循环的语句与C语言中相同,我们可以用while、do-while、for三种方式实现循环
while
使用用循环实现连续判断
其实上面连续判断的例子中,我们似乎就是在不断地重复,一个一个的判断选项,直到找到正确的答案,因此他也可以使用循环实现,此处以while为例:
题目:
1+1=?
A.0, B.1, C.2
String[] answers = {"A", "B", "C"};//answers[0] = A ,answers[1] = B ,answers[2] = C
int i = 0;
int result = 2 - 1;
while (i<=answers.length){
System.out.println(i);
if (i == result){
System.out.println(answers[i]);
}
i++;
}
// 输出
0
1
B
2
其中i<=answers.length为退出条件,而{}包裹起来的line5-line8为循环体。while语句的执行逻辑是:
-
判断进入条件
-
不符合进入条件,退出循环向下执行。
-
符合进入条件,进入循环
-
执行完循环体,回到step1
因此以上示例的语义是,判断i是否超出答案范围,没超出就进来查看i是不是最终答案,是的话就输出,不断循环,直到答案数组循环完毕。
循环控制语句break/continue
break
break语句在循环中使用时,用于控制程序直接结束当前循环流程。
我们可以看到,以上的循环代码,是不断依次查看答案,直到所有答案搜索完毕,不管是否已经找到了正确答案。而实际上我们真正做题的时候,如果找到了正确的答案后就不应该继续向下搜索因为毫无意义。因此我们可以使用break代码优化以上循环:
String[] answers = {"A", "B", "C"};
int i = 0;
int result = 2 - 1;
while (i<=answers.length){
if (i == result){
System.out.println(answers[i]);
break;
}
i++;
}
// 输出
0
1
B
continue
continue语句专门在循环中使用,用于跳过这一圈循环,进入下一圈循环。
不知道读者有没有玩过一个多人的游戏,叫做“拍7”。
游戏规则如下:
游戏人数>1
-
参与者一次按照顺序报数。
-
如果遇到7的倍数,不可以报出数字,要拍一下手表示跳过。
-
一旦有人报出了7的倍数,视为违规,要接受惩罚。
下面我们使用continue和计算机一起进行从1到30的”拍7“:
int i = 1;
while (i<=30){
if (i % 7 == 0){
System.out.print("拍,");
i++;
continue;
}
System.out.printf("%d,",i);
i++;
}
// 输出:
1,2,3,4,5,6,拍,8,9,10,11,12,13,拍,15,16,17,18,19,20,拍,22,23,24,25,26,27,拍,29,30,
do-while
do-while的语法和while类似
do{
// body
}while(exp)
不同于while现判断进入语句再进入循环,do-while是先斩后奏,先执行循环体,然后判断是否需要退出循环,即使exp的值一开始就是false,也会至少执行一次body的内容
for
for基本语法
for循环其实是我们实际编程中用到最多的循环,我们使用for循环的方式实现一下判断题的例子,观察有何不同:
String[] answers = {"A", "B", "C"};//answers[0] = A ,answers[1] = B ,answers[2] = C
int result = 2 - 1;
for (int i = 0;i<=answers.length;i++){
System.out.println(i);
if (i == result){
System.out.println(answers[i]);
break;
}
}
计数器
我们可以观察到,在条件表达式的位置,不只有“i<=answers.length”这个退出条件,前后还有两个语句被“;”分隔,他们分别是“int i = 0”和“i++”。同样上面while的例子中,读者可以看到,我们声明了一个int i,然后每次循环结束,我们都要执行i的自增i++,并且使用i的值是否达到限制作为退出条件,我们称这个变量i为:循环计数器。而for循环和while循环的主要区别就是for默认需要循环计数器的声明和循环的“步进”。
break/continue
当然我们也可以观察到,break语句再for循环中依然适用,当然continue也一样。
foreach
针对上面例子这种,依次循环查看数组元素,或者我们后面会学习到的“集合”的元素时,for循环有一种简便的写法,我们成为foreach或者for-in:
String[] answers = {"A", "B", "C", "B"};//answers[0] = A ,answers[1] = B ,answers[2] = C
String target = "B";
int count = 0;
for (String answer : answers) {
if (answer == target){
count++;
}
}
System.out.println(count);
// 输出
2
上面程序实现了在一个String数组中统计B字母的数量。
总结
由此我们已经学习完了关于选择和循环的控制流:
最基本的两项分支:非此即彼->if-else,由此之上我们扩展了连续判断->if-else if以及如何使用return语句来简化他们。
但是对于多项分支的判断,if-else if还是稍显冗余,因此我们引入了switch语句,清晰而简洁!
另外有一条原则需要注意,在以后的的编程中,我们遇到复杂的分支选择时,应该改尽量避免过多层的if-else判断,我们已经在if-else if一节中见证了这对于代码的阅读和维护是怎样一场灾难。因此当分支较多时,请果断选择switch或者对更复杂的分支,请使用设计模式来解决。
关于循环我们学会了while,do-while, for(for-in)语句如何实现循环以及循环的控制语句break和continue如何控制循环流程。