【西行 - 大圣闹天宫】 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 语句后,程序立马结束,不管循环多少次或多少层。

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

目录
相关文章
|
12月前
|
前端开发 Java API
2025 年 Java 全栈从环境搭建到项目上线实操全流程指南:Java 全栈最新实操指南(2025 版)
本指南涵盖2025年Java全栈开发核心技术,从JDK 21环境搭建、Spring Boot 3.3实战、React前端集成到Docker容器化部署,结合最新特性与实操流程,助力构建高效企业级应用。
3192 1
|
消息中间件 Java Kafka
Java 事件驱动架构设计实战与 Kafka 生态系统组件实操全流程指南
本指南详解Java事件驱动架构与Kafka生态实操,涵盖环境搭建、事件模型定义、生产者与消费者实现、事件测试及高级特性,助你快速构建高可扩展分布式系统。
529 7
|
12月前
|
消息中间件 Java 数据库
Java 基于 DDD 分层架构实战从基础到精通最新实操全流程指南
本文详解基于Java的领域驱动设计(DDD)分层架构实战,结合Spring Boot 3.x、Spring Data JPA 3.x等最新技术栈,通过电商订单系统案例展示如何构建清晰、可维护的微服务架构。内容涵盖项目结构设计、各层实现细节及关键技术点,助力开发者掌握DDD在复杂业务系统中的应用。
2019 0
|
自然语言处理 前端开发 Java
JBoltAI 框架完整实操案例 在 Java 生态中快速构建大模型应用全流程实战指南
本案例基于JBoltAI框架,展示如何快速构建Java生态中的大模型应用——智能客服系统。系统面向电商平台,具备自动回答常见问题、意图识别、多轮对话理解及复杂问题转接人工等功能。采用Spring Boot+JBoltAI架构,集成向量数据库与大模型(如文心一言或通义千问)。内容涵盖需求分析、环境搭建、代码实现(知识库管理、核心服务、REST API)、前端界面开发及部署测试全流程,助你高效掌握大模型应用开发。
1193 5
|
Java 编译器
Java 17 Switch表达式:更简洁、更强大的流程控制
Java 17 Switch表达式:更简洁、更强大的流程控制
1270 111
|
安全 Java 程序员
《从头开始学java,一天一个知识点》之:控制流程:if-else条件语句实战
**你是否也经历过这些崩溃瞬间?** - 看了三天教程,连`i++`和`++i`的区别都说不清 - 面试时被追问&quot;`a==b`和`equals()`的区别&quot;,大脑突然空白 - 写出的代码总是莫名报NPE,却不知道问题出在哪个运算符 这个系列为你打造Java「速效救心丸」!每天1分钟,地铁通勤、午休间隙即可完成学习。直击高频考点和实际开发中的「坑位」,拒绝冗长概念,每篇都有可运行的代码示例。明日预告:《for与while循环的使用场景》。 ---
400 19
|
JavaScript Java 微服务
现代化 Java Web 在线商城项目技术方案与实战开发流程及核心功能实现详解
本项目基于Spring Boot 3与Vue 3构建现代化在线商城系统,采用微服务架构,整合Spring Cloud、Redis、MySQL等技术,涵盖用户认证、商品管理、购物车功能,并支持Docker容器化部署与Kubernetes编排。提供完整CI/CD流程,助力高效开发与扩展。
1179 64
|
12月前
|
JavaScript 安全 前端开发
Java开发:最新技术驱动的病人挂号系统实操指南与全流程操作技巧汇总
本文介绍基于Spring Boot 3.x、Vue 3等最新技术构建现代化病人挂号系统,涵盖技术选型、核心功能实现与部署方案,助力开发者快速搭建高效、安全的医疗挂号平台。
495 3
|
安全 Java 数据库
使用Java实现用户的注册和登录流程
以上提供了用户注册和登录的基本框架和必要的说明。在具体的应用场景中,可能还需结合框架特性如Spring Security等提供的高级特性来实现更为完备和安全的用户认证机制。在开发期间,务必注重代码的安全性、清晰性和可维护性,为用户资料保驾护航。
762 13
|
人工智能 Cloud Native Java
Java 技术栈企业级应用开发全流程
本指南通过构建企业级电商系统,全面解析现代化Java技术栈实战应用。涵盖Spring Boot 3、微服务架构、云原生部署、服务治理、监控可观测性及AI集成,助开发者掌握全流程开发技能,打造高效可扩展的企业级应用。
747 0
Java 技术栈企业级应用开发全流程