【西行 - 大圣闹天宫】 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 次。


嵌套循环执行流程如下图。


image.png


从流程图中我们可以看出,嵌套循环就是把内层循环当成外层循环的循环体。


当只有内层循环的循环条件为 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 语句后,程序立马结束,不管循环多少次或多少层。

好了,今天的内容到这里就结束了,关注我,我们下期见

目录
相关文章
|
28天前
|
缓存 监控 Java
Java线程池提交任务流程底层源码与源码解析
【11月更文挑战第30天】嘿,各位技术爱好者们,今天咱们来聊聊Java线程池提交任务的底层源码与源码解析。作为一个资深的Java开发者,我相信你一定对线程池并不陌生。线程池作为并发编程中的一大利器,其重要性不言而喻。今天,我将以对话的方式,带你一步步深入线程池的奥秘,从概述到功能点,再到背景和业务点,最后到底层原理和示例,让你对线程池有一个全新的认识。
55 12
|
6月前
|
Java
解析Java线程池:参数详解与执行流程
解析Java线程池:参数详解与执行流程
69 1
|
1月前
|
小程序 前端开发 算法
|
1月前
|
Java API 开发者
Java如何实现企业微信审批流程
大家好,我是V哥。本文分享如何在企业微信中实现审批流程,通过调用企业微信的开放API完成。主要内容包括获取Access Token、创建审批模板、发起审批流程和查询审批结果。提供了一个Java示例代码,帮助开发者快速上手。希望对你有帮助,关注V哥爱编程,编码路上同行。
100 4
|
2月前
|
SQL IDE Java
入门Cloud Toolkit:简化你的Java应用开发与部署流程
【10月更文挑战第19天】作为一名长期从事Java开发的程序员,我一直致力于寻找能够简化日常开发工作的工具。在众多工具中,阿里巴巴推出的Cloud Toolkit引起了我的注意。这款免费的插件旨在帮助开发者更轻松地进行开发、测试及部署工作,尤其是在与云服务交互时表现尤为出色。本文将从个人的角度出发,介绍Cloud Toolkit的基本功能及其使用技巧,希望能帮助初学者快速上手这款实用工具。
36 1
|
5月前
|
消息中间件 存储 Java
使用Java构建实时数据处理流程
使用Java构建实时数据处理流程
|
2月前
|
前端开发 安全 Java
java发布公告的实现流程
构建一个Java公告发布系统涉及到前端界面设计、后端业务逻辑处理、数据库设计与交互、安全性保障等多个环节。通过采用现代的开发框架和最佳实践,可以高效地开发出既安全又易于维护的系统。随着需求的增长,系统还可以进一步扩展,比如增加评论功能、通知订阅、多语言支持等。
51 1
|
2月前
|
运维 Cloud Native Java
Java项目部署的发展流程
本文介绍了四种不同的应用部署方式:传统部署、虚拟化部署、容器化部署和云原生部署。每种方式的特点、部署流程及优缺点进行了详细说明。传统部署直接在物理机上运行应用,存在资源利用率低和运维成本高的问题;虚拟化部署通过虚拟机实现资源隔离和复用,但有性能损失和单点故障风险;容器化部署则提供轻量级、可移植的应用环境,具备良好的隔离性和一致性;云原生部署结合了容器化和微服务架构,实现高效运维和灵活扩展。
Java项目部署的发展流程
|
4月前
|
运维 Cloud Native Java
Java项目部署的发展流程
本文对比分析了四种不同的应用部署方式:传统部署、虚拟化部署、容器化部署及云原生部署。传统部署直接在物理机上运行程序,存在资源复用难等问题。虚拟化部署通过虚拟机技术实现了资源的有效隔离与利用,但可能会造成性能损失。容器化部署则进一步提升了应用的可移植性和资源利用率,减轻了运维负担。云原生部署结合容器化、微服务等技术,实现了应用的快速迭代、高效运维和灵活扩展,适用于现代互联网应用的开发与部署。每种方式均针对其特点进行了详细的流程描述与优缺点分析。
|
4月前
|
安全 Java 编译器
Java 基础语法-面试题(53道)(基础概念+基础语法+流程控制)
Java 基础语法-面试题(53道)(基础概念+基础语法+流程控制)
73 18