- J3 - 白起
- Java(Java基础 # 流程控制 # 笔记)
不论是哪种编程语言,都会提供两种基本的流程控制结构:分支结构和循环结构。
分支结构用于实现根据条件选着性的执行某段代码,循环结构则是用于实现循环条件重复执行某段代码。
Java 中同样提供了这两种流程控制语法:
- 分支语句:if、switch。
- 循环语句:while、do while、for 以及JDK1.5 后的 foreach循环。
1、顺序结构
任何编程语言中,最常见的程序结构就是顺序结构。
顺序结构指程序从上到下逐行地执行,中间没有任何判断和跳转。
在 main 方法中多行代码之间没有任何流程控制,则程序总是从上向下一次执行,排在前面的代码先执行,排在后面的代码后执行。
2、分支结构
Java 提供了两种常见的分支控制结构:
- if
- switch
if 语句使用布尔表达式或布尔值作为分支条件进行分支控制;而 switch 语句则用于对多个整型值(Java 7 支持String类型)进行匹配,从而实现分支控制。
2.1 if 条件语句
if 语句有下列三种形式。
第一种:
if (条件表达式){
// 逻辑代码
}
第二种:
if (条件表达式){
// 逻辑代码
}else {
// 逻辑代码
}
第三种:
if (条件表达式1){
// 逻辑代码
}else if (条件表达式2){
// 逻辑代码
}else if (条件表达式3){
// 逻辑代码
}
...省略多个 else if 语句
else {
// 逻辑代码
}
三种类型类型中,条件表达式的返回值只能是 true 或者 false。
在上面的条件语句中,if (表达式) 、else if (表达式) 和 else 后花括号括起来的多行代码被称为代码块,一个代码块通常被当成一个成体来执行(除非运行过程中遇到 return、break、continue 等关键字,或者遇到了异常),因此这个代码块也被称为条件执行体。例如如下代码。
public class BranchTest {
public static void main(String[] args) {
int age = 18;
if (age == 18){
// 只有当 age 等于 18 时下面的两个输出语句才会执行
System.out.println("噢噢噢!原来 J3 才 18 岁。");
System.out.println("不愧是靓仔");
}
System.out.println("一个毫无意义的输出,就像 J3 还认为自己 18 岁。");
}
}
如果 if(表达式)、else if(表达式)和 else 后的代码只有一行语句是,则可以省略花括号,因为单行语句本身就是一个整体,无须用括号来把它们定义成一个整体。例如下面代码完全可以执行。
public class BranchTest {
public static void main(String[] args) {
int age = 17;
if (age > 18)
System.out.println("J3 老是拿年龄做文章,都不敢正视自己的年纪!!!");
else
System.out.println("嘿嘿!我要让上面的语句不能输出,敢质疑我,哼!");
}
}
但,通常我们是不建议这样做的,即时条件执行体只有一条语句,也要保留花括号,因为可读性较好,而且这会减少错误发生的可能。
例如下面代码和想象的结果可能有不同。
public class BranchTest {
public static void main(String[] args) {
int age = 19;
if (age > 18)
System.out.println("J3 老是那年龄做文章,都不敢正视自己的年纪!!!");
else
System.out.println("嘿嘿!我要让上面的语句不能输出,敢质疑我,哼!");
// 这个输出永远会执行
System.out.println("J3 永远是 18");
}
}
System.out.println("J3 永远是 18")
这个语句永远会执行的原因就是它不是 else 后的条件执行体。
如果,if 后面有多条语句作为条件执行体,若省略了这个条件执行体的花括号,则会引起编译错误。例如下面代码。
public class BranchTest {
public static void main(String[] args) {
int age = 19;
if (age > 18)
System.out.println("J3 老是那年龄做文章,都不敢正视自己的年纪!!!");
System.out.println("这个输出写在这,是会报错的在没有花括号的时候!!!!!");
else
System.out.println("嘿嘿!我要让上面的语句不能输出,敢质疑我,哼!");
// 这个输出永远会执行
System.out.println("J3 永远是 18");
}
}
2.2 switch分支语句
switch 语句由一个控制表达式和多个 case 标签组成,和 if 语句不同的是,switch 语句后面的控制表达式的数据类型只能是 byte、short、char、int 四个整数类型和枚举类型,不能是 boolean 类型。
Java 7 改进了 switch 分支语句,Java 7 允许 switch 语句中的控制表达式为 java.lang.String 类型。
switch 语句往往需要在 case 标签后紧跟着一个代码块,case 标签作为这个代码块的标识。语法格式如下。
public class BranchTest {
public static void main(String[] args) {
switch (表达式){
case 情况1:{
// 逻辑1
break;
}
case 情况2:{
// 逻辑2
break;
}
...
default:{// 都不满足,则默认执行这个
// 默认逻辑
}
}
}
}
这种分支语句的执行先是对表达式求值,然后依次匹配情况1、情况2、…等值,遇到匹配的值及执行对应的执行体;如果所有 case 标签后的值都不与表达式的值相等,则执行 default 标签后的代码块。
和 if 语句不同的是,switch 语句中各个 case 标签后代码块的开始点和结束点非常清晰,因此完全可以省略 case 后面的花括号。
与 if 语句中的 else 类似,当 switch 表达式中的值没有任何一种情况匹配时,就会执行 default 后面的代码块。
switch 使用案例如下。
public class BranchTest {
public static void main(String[] args) {
char name = 'J';
switch (name){
case 'A':{
System.out.println("name 等于 A");
break;
}
case 'B':{
System.out.println("name 等于 B");
break;
}
case 'J':{
System.out.println("name 等于 J");
break;
}
default:{
System.out.println("name 啥也不是!");
}
}
}
}
运行结果输出了 “name 等于 J” 符合我们的预期。
看代码我们发现,每个 case 标签后面都有一条 break;语句,这个 break;语句还是挺重要的,如果把上面代码的 break;都去掉那么结果会是如下情况。
name 等于 J
name 啥也不是!
看起来有点奇怪,但这就是由 switch 语句的运行流程决定的。
switch 语句会先求出表达式的值,然后和 case 标签后的值进行比较,一旦遇到相等的值,就开始执行 cases 标签后面的代码,并不在判断后面 case、default 标签的条件是否匹配,除非是遇到 break;才会结束。
Java 7 增强了 switch 语句的功能,允许 switch 语句的控制表达式是 java.lang.String 类型的变量或者表达式(只允许了 java.lang.String 其他类型字符串不行)。例如如下代码。
public class BranchTest {
public static void main(String[] args) {
String blogType = "CSDN";
switch (blogType){
case "CSDN":{
System.out.println("J3,CSDN老牌用户,新人作者!");
break;
}
case "juejin":{
System.out.println("J3,掘金新用户,新人作者");
break;
}
case "zhihu":{
System.out.println("J3,知乎新用户,新人作者");
break;
}
default:{
System.out.println("J3,啥也不是!");
}
}
}
}
在使用 switch 时,有两个地方值得注意:
- switch 表达式类型只能是 byte、short、char、int、String。
- 如果 case 标签后的代码省略了 break;则会一直往下执行直到碰到 break;。
3、循环结构
在循环语句中,满足循环条件的情况下,可以反复执行一段代码,重复执行的代码称为循环体。
循环结构需要注意的是,循环条件。当循环条件永远为 true 时会造成死循环。
3.1 while 循环语句
while 循环的语法格式如下:
while (表达式或布尔值) {
// 循环体代码
}
在执行 while 循环体之前,先对表达式求值,如果条件为 true,则运行循环体部分。
下面演示一个简单的 while 循环。
public class CycleTest {
public static void main(String[] args) {
int i = 1;
int sum = 0;
while (i <= 10) {
// 循环,求 1 到 10 的和。
sum = sum + i;
i = i + 1;
}
System.out.println("1 到 10 的累加和:" + sum);
}
}
值得注意的是 i <= 10
这个表达式的结果要在某个时刻变为 false ,不然程序会进行死循环,造成程序永远无法结束。
3.2 do while 循环语句
do while 循环与 while 循环的区别在于:while 循环是先判断循环条件,如果条件为真则执行循环体;而 do while 循环则先执行循环体,然后才判断循环条件,如果循环条件为真,则执行下一次循环,否则终止循环。
do while 语法格式如下。
do {
循环体
}while (表达式);
注意,while 的后面是要跟一个分号,表明循环结束。
下面看看简单用法。
public class CycleTest {
public static void main(String[] args) {
int age = 16;
do {
System.out.println("时间,一年年的过去,转眼我 J3 已经:" + age + "岁了。");
age = age + 1;
} while (age < 25);
System.out.println("转眼我都这么大了~");
}
}
由程序我们可以发现,do while 循环不管表达式条件真假,都会执行一遍循环体。
3.3 for 循环
for 循环是一个更加简洁的循环语句,大部分情况下,for 循环可以替代 while 循环、do while 循环。
for 循环的基本语法格式如下。
for (初始化值; 循环条件 ; 迭代语句) {
循环体
}
程序执行 for 循环时,先执行循环的初始化值,初始化值语句只在循环开始前执行一次。
每次执行循环体之前,先判断循环条件的真假,true 执行循环体,执行循环体完成之后再执行迭代语句。
因为是先判断循环条件真假,在执行循环体,所以循环条件总要比循环体多执行一遍。
简单使用案例如下。
public class CycleTest {
public static void main(String[] args) {
int sum = 0;
for (int i = 1; i <= 10; i++) {
sum = sum + i;
System.out.println("我被执行了第 " + i + " 次。");
}
System.out.println("1 到 10 的累加和:" + sum);
}
}
当然,对于初始化语句是允许指定多个初始语句,循环条件也是可以包含逻辑运算表达式。程序如下。
public class CycleTest {
public static void main(String[] args) {
for (int i = 0, b = 2, c = 3; i <= 7 && b < 8 && c < 9; i++) {
System.out.println("我执行了~~~~~~~");
}
}
}
上面代码中初始化变量有三个,但只能有一个声明语句,因此如果需要在初始化表达式中声明多个变量,那么这些变量应该具有相同的数据类型。
在 for 循环括号中只有两个分号是必须的,初始化语句、循环条件、迭代语句部分都是可以省略的,如果省略了循环条件,则这个循环条件模式 true ,将会产生一个死循环。例如下面程序。
public class CycleTest {
public static void main(String[] args) {
for (; ; ) {
System.out.println("我将要进行死循环输出了~~~");
}
}
}
上面代码将进行死循环,一直输出 我将要进行死循环输出了~~~
字符串。
使用 for 循环还是以写成如下形式。
public class CycleTest {
public static void main(String[] args) {
// 初始语句
int i = 1;
for (; i <= 10 ; ) {
System.out.println("我是变种 for 循环!");
// 迭代语句
i = i +2;
}
}
}
这种写法与 while 的形式很类似,并且这种写法的初始值 i 即时在 for 循环体外也是可以访问的,而初始化语句写在括号里面的话,则只能在循环体中使用(变量作用范围,后面介绍)。
3.4 嵌套循环
如果把一个循环放在另一个循环体内,那么就可以形成嵌套循环了,嵌套循环既可以是 for 循环嵌套 while 循环,也可以是 while 循环嵌套 do while 循环…既各种类型的循环都可以作为外层循环,各种类型的循环也可以作为内层循环。
当外层循环的循环次数为 n 次,内层循环的循环次数为 m 次,那么内层循环的循环体实际上需要执行 n * m 次。
嵌套循环执行流程如下图。
从流程图中我们可以看出,嵌套循环就是把内层循环当成外层循环的循环体。
当只有内层循环的循环条件为 false 时,才会完全跳出内层循环,才可以结束外层循环的当次循环,开始下一次循环,下面看个简单案例。
public class NestedTest {
public static void main(String[] args) {
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= i; j++) {
System.out.print( j + " * " + i + " = " + i * j + " ");
}
System.out.println("");
}
}
}
程序执行结果是一个九九乘法表,通过前面知识积累,相信理解起来不费劲。
实际上,嵌套循环不仅可以嵌套两层,只要你愿意,多少层都是可以的。但不管如何嵌套循环,我们都可以吧内层循环当成外层循环体来对待,区别只是这个循环体包含了需要反复执行的代码。
4、控制循环结构
Java 语言没有提供 goto 语句来控制程序的跳转,这种做法提高了流程控制的可读性,但降低了程程控制的灵活性。
为了弥补这种不足, Java 提供了 continue
和 break
来控制循环结构。除此之外,return 可以结束整个方法,当然也就是结束一次循环了。
4.1 break 结束循环
循环的时候我们不一定要等到循环条件为 false 的时候才退出循环,使用 break 就可以强行终止循环。
在循环中,一旦循环体中遇到 break ,系统将完全结束该循环,开始执行循环之后的代码。例如下面程序。
public class NestedTest {
public static void main(String[] args) {
for (int i = 1; i <= 10000; i++) {
System.out.println("我在循环 一万次!");
if (i == 10){
System.out.println("让你执行 1 万次,疯了,不行,我要结束你!");
break;
}
}
System.out.println("结束了");
}
}
break 语句不仅可以结束其所在的循环,还可以直接结束外层循环。此时需要在 break 后紧跟一个标签,这个标签用于表示一个外层循环。
Java 中的标签就是一个紧跟着英文冒号(:)的标识符。与其他语言不同的是,Java 中的标签只有放在循环语句之前才有作用。例如下面代码。
public class NestedTest {
public static void main(String[] args) {
// 外层循环,outo 作为标识符
outo:
for (int i = 1; i <= 100; i++) {
for (int j = 1; j <= 100; j++) {
System.out.println("我又在循环 1 万次!");
if ( (i * j) > 10){
System.out.println("给你脸了,又来循环 1 万次,给我全部结束,不要执行了!");
// 跳出 outo 标签所在标识的循环
break outo;
}
}
}
System.out.println("我结束了!");
}
}
程序从外层循环进入内层循环后,当 i * j > 10 后,程序遇到一个 break outo;语句,这行代码将会导致结束 outo 标签指定的循环,不是结束 break 所在的循环,而是结束 break 玄幻的外层循环。
通常紧跟 break 之后的标签,必须在 break 所在的循环的外层循环之前定义才有意义。
4.2 continue 结束本次循环
continue 的功能和 break 有点类似,区别是 continue 只是终止本次循环,接着开始下次循环;而 break 则是完全终止循环本身。可以理解为 continue 的作用是跳过当次循环中剩下的语句,重新开始一次新的循环。例如下面代码。
public class NestedTest {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
System.out.println("我是 i = " + i + " 前面的语句");
if (i <= 3){
continue;
}
System.out.println("我是 i = " + i + " 后面的语句");
}
}
}
当 i 小于等于 3 的时候 if 下面的语句没有输出,因为程序走了 if 体里面的 continue ,忽略了当次循环,开始了新循环。
与 break 类似的是,continue 后也可以紧跟一个标签,用于直接跳过标签所在标识循环的当次循环的剩下语句,重新开始下一次循环。例如下面代码。
public class NestedTest {
public static void main(String[] args) {
outo:
for (int i = 1; i < 10; i++) {
for (int j = 1; j < 5; j++) {
System.out.println("这人又来 for 循环了~~~");
if (i * j > 8) {
System.out.println("只能执行到这了,下面的就先跳过吧,不用执行了");
continue outo;
}
System.out.println("内层循环,我是否能被执行到!!!");
}
System.out.println("======外层循环,我是否能被执行到!!!");
}
}
}
当程序执行到 continue outo 语句时,直接跳过了内层循环和外层循环,执行了外层的下一次循环。
与 break 类似的是,continue 后的标签也必须是一个有效标签,即这个标签通常应该放在 continue 所在循环的外层循环之前定义。
4.3 return 结束方法
return 关键字并不是专门用于结束循环的,return 的功能是结束一个方法。当一个方法执行到 return 语句时(return 关键字后还可以跟变量、常量和表达式,后面会介绍),这个方法将被结束。
例如下面代码会结束改方法。
public class NestedTest {
public static void main(String[] args) {
for (int i = 0; i < 100000; i++) {
System.out.println("我又在不停的循环中...");
if (i > 10){
System.out.println("过分,1 万都不让你循环,你还循环 10 次,做梦,我要终结整个方法。");
return;
}
}
}
}
上面代码,碰到 return 语句后,程序立马结束,不管循环多少次或多少层。
好了,今天的内容到这里就结束了,关注我,我们下期见
查阅或参考资料:
《Java核心技术第10卷》
《疯狂 Java 讲义》
联系方式:
QQ:1491989462,做个好友,来个点赞之交。
-
由于博主才疏学浅,难免会有纰漏,假如你发现了错误或偏见的地方,还望留言给我指出来,我会对其加以修正。
-
如果你觉得文章还不错,你的转发、分享、点赞、留言就是对我最大的鼓励。
-
感谢您的阅读,十分欢迎并感谢您的关注。
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
个人站点:J3
CSDN:J3 - 白起
掘金:J3-白起
知乎:J3-白起
这是一个技术一般,但热衷于分享;经验尚浅,但脸皮够厚;明明年轻有颜值,但非要靠才华吃饭的程序员。
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^