11-程序流控制

目录

1.分支语句

1.1.if语句:使程序能够基于某种条件有选择地执行某些语句。

1.2.switch语句:基于一个表达式的值决定要执行的一组语句。

PS:switch语句扩展与switch表达式

2.循环语句

2.1.while语句:使一个语句块在某种条件为真时循环执行,执行前不知循环次数。

2.2.do while语句:执行前不知循环次数。

2.3.for语句:循环执行的次数是可以在执行前确定的。

PS:for-each语句

3.循环跳转语句:break和continue

3.1.break语句:

3.1.1.带标签

3.1.2.不带标签

3.2.continue语句:

3.2.1.带标签

3.2.2.不带标签

PS:return语句

4.异常处理语句

4.1.捕获异常:try catch finally语句。

4.2.抛出异常:throw语句。


在结构化程序设计中规定三种基本流程结构:顺序结构(比较简单,按照代码的书写顺序一行一行执行,如果调整代码的书写顺序,则执行顺序也发生变化)、分支结构循环结构

程序流控制语句可以使程序运行时,有条件地执行或重复执行某些语句,改变程序正规的顺序执行流向。Java语言提供了4类程序流控制语句。

  • 分支语句
  • 循环语句
  • 跳转语句
  • 异常处理语句

1.分支语句

1.1.if语句:使程序能够基于某种条件有选择地执行某些语句。

基本语法形式1:

if(布尔表达式){
   //条件满足时执行代码
}

基本语法形式2:

if(布尔表达式){
   //条件满足时执行代码
}else{
   //条件不满足时执行代码
}

基本语法形式3:多分支的情况

if(布尔表达式){
   //条件满足时执行代码
}else if(布尔表达式){
   //条件满足时执行代码
}else{
   //条件都不满足时执行代码
}

注:

1).区别:

if( ){ }

if( ){ }

是两个可能都走。

if( ){ }

else if( ){ }

要么走上要么走下。

2).条件运算符"? : "是if else语句的一种紧缩格式的表达。

3).悬垂else问题

int x = 10;
int y = 10;
if (x == 10)
    if (y == 10)
        System.out.println("aaa");
else
    System.out.println("bbb");
//运行结果
aaa

 if else语句中不加大括号也可以写语句(只能写一条语句)。此时else是和最接近的if匹配(就近原则)。但是实际开发中不建议这么写,最好加上大括号。

4).代码风格问题

// 风格1
int x = 10;
if (x == 10) {
// 满足条件
} else {
// 不满足条件
}

// 风格2
int x = 10;
if (x == 10)
{
// 满足条件
}
else
{
// 不满足条件
}

虽然两种方式都是合法的,但是 Java 中更推荐使用风格1,{ 放在 if else 同一行。

5).分号问题

int x = 20;
if (x == 10); {
System.out.println("hehe");
}
// 运行结果
hehe

此处多写了一个分号, 导致分号成为了 if 语句的语句体, 而 { } 中的代码已经成为了一个和 if 无关的代码块。

1.2.switch语句:基于一个表达式的值决定要执行的一组语句。

基本语法:

switch(整数|枚举|字符|字符串){
    case 内容1 : 
         内容满足时执行语句(组);
         break; 
    case 内容2 : 
         内容满足时执行语句(组);
         break;
    ...
    [default:
         内容都不满足时执行语句(组);
         break;]
}

根据 switch 中值的不同,会执行对应的 case 语句。遇到 break 就会结束该 case 语句。
如果 switch 中的值没有匹配的 case,就会执行 default 中的语句。我们建议一个 switch 语句最好都要带上 default(default子句是可选的,并且最后一个break语句可省略)。

注:

1).switch语句中各case分支既可以是单条语句,也可以是由多条语句组成的语句组,该语句组可以不用{ }括起来。

2).break不要遗漏,否则会失去"多分支选择"的效果。

int day = 1;
switch(day) {
    case 1:
         System.out.println("星期一");
         // break;
    case 2:
         System.out.println("星期二");
         break;
}
// 运行结果
星期一
星期二

发现不写 break 的时候, case 语句会依次向下执行, 从而失去了多分支的效果。

switch在每个case后面要加上break表示终止;若没有break终止,当switch遇到满足条件的分支后,会一直执行到switch最后。

3).switch中的值只能是 整数|枚举|字符|字符串。

double num = 1.0;
switch(num) {
     case 1.0:
          System.out.println("hehe");
          break;
     case 2.0:
          System.out.println("haha");
          break;
}
// 编译出错
Test.java:4: 错误: 不兼容的类型: 从double转换到int可能会有损失

4).switch不能表达复杂的条件。

// 例如: 如果 num 的值在 10 到 20 之间, 就打印 hehe
// 这样的代码使用 if 很容易表达, 但是使用 switch 就无法表示.
if (num > 10 && num < 20) {
    System.out.println("hehe");
}

5).switch 虽然支持嵌套, 但是很丑。

int x = 1;
int y = 1;
switch(x) {
   case 1:
        switch(y) {
               case 1:
                    System.out.println("hehe");
                    break;
        }
        break;
   case 2:
        System.out.println("haha");
        break;
}

代码的美观程度也是一个重要的标准,毕竟这是看脸的世界。

综上发现,switch 的使用局限性是比较大的。

PS:switch语句扩展与switch表达式

Java SE 12和Java SE 13对switch进行了扩展,解决了上述问题。

switch的扩展,主要体现在case分支的定义,有两种形式:

a.传统的"case... : "分支(冒号case)

b.新的"case... -> "分支(箭头case)

case label_1, label_2, ... ,label_n -> expression; | throw - statement; | block

上述定义中:

1).允许在一个case分支里出现以逗号分隔的多个常量值。程序运行时,这些值中的任何一个匹配成功,箭头右侧的代码都将被运行,并且在这些代码结束后,将不会运行switch表达式或语句中任何其他分支中的代码。因此,箭头case解决了传统冒号case的控制流贯穿问题。

2).箭头右侧的代码可以是一个表达式,一个throw语句或一个语句块(包含多个语句)。

在语句块中声明的局部遍历,其作用域只是所在的语句块而不是整个switch语句。

如果箭头右侧是一个表达式,则该表达式的值将是switch表达式的值。

箭头case的switch语句:

int numLetters = 0;
Day day = Day.WEDNESDAY;
switch(day){
    case MONDAY, FRIDAY, SUNDAY -> numLetters = 6;
    case TUESDAY -> numLetters = 7;
    case THURSDAY, SATURDAY -> numLetters = 8;
    case WEDNESDAY -> numLetters = 9;
    default -> throw new IllegalStateException("Invalid day: " + day);
};
System.out.println(numLetters);

箭头case的switch表达式:

Day day = Day.WEDNESDAY;
System.out.println(
    switch(day){
        case MONDAY, FRIDAY, SUNDAY -> 6;
        case TUESDAY -> 7;
        case THURSDAY, SATURDAY -> 8;
        case WEDNESDAY -> 9;
        default -> throw new IllegalStateException("Invalid day: " + day);
    }
);

Java SE 13中引入了yield语句,定义为:

yield someValue

其中someValue是yield所在case分支产生的switch表达式的值。

int j = switch(day){
    case MONDAY -> 0;
    case TUESDAY -> 1;
    default -> {
         int k = day.toString().length();
         int result = f(k);
         yield result;
    }
};

break和yield语句使得switch语句和switch表达式易于区分:

yield语句用于switch表达式,break语句用于switch语句。

传统的冒号case可以使用yield语句构造switch表达式。

int result = switch(s){
    case "Foo":
          yield 1;
    case "Bar":
          yield 2;
    default:
          System.out.println("Neither Foo nor Bar, hmmm...");
          yield 0;
};

2.循环语句

2.1.while语句:使一个语句块在某种条件为真时循环执行,执行前不知循环次数。

基本语法

while(循环条件){
     循环语句;
}

循环条件(逻辑表达式)为 true,则执行循环语句;否则false结束循环。

注:

1).和 if 类似, while 下面的语句可以不写 { },(只支持一条语句),建议加上 { }。

2).和 if 类似, while 后面的 { 建议和 while 写在同一行。

3).和 if 类似, while 后面不要多写分号,否则可能导致循环不能正确执行。

int num = 1;
while (num <= 10); {
    System.out.println(num);
    num++;
}
// 执行结果
[无任何输出, 程序死循环]

此时 ; 为 while 的语句体(这是一个空语句),实际的 { } 部分和循环无关。此时循环条件 num <= 10 恒成立,导致代码死循环了。

2.2.do while语句:执行前不知循环次数。

基本语法:

do{
   循环语句;
}while(循环条件);

先执行循环语句,再判定循环条件。至少把循环体中的语句执行一遍。

注:

1).do while 循环最后的分号不要忘记。

2).一般 do while 很少用到,更推荐使用 for 和 while。

2.3.for语句:循环执行的次数是可以在执行前确定的。

基本语法:

for(初始语句;逻辑表达式;迭代语句){
    语句或语句块;
}
  • 初始语句: 用于初始化循环变量。
  • 逻辑表达式: 循环条件。
  • 迭代语句: 更新循环变量。

for语句执行时先执行初始语句,判断逻辑表达式的值,当逻辑表达式为true时,执行循环体语句,接着执行迭代语句,然后再去判断逻辑表达式的值。这个过程一直进行下去,直到逻辑表达式的值为false,循环结束并转到for之后的语句。

注:(和while循环类似)

1).和 if 类似, for 下面的语句可以不写 { } ,(只支持一条语句),建议加上 { }。

2).和 if 类似, for 后面的 { 建议和 for写在同一行。

3).和 if 类似, for 后面不要多写分号, 否则可能导致循环不能正确执行。

4).可以在for循环的初始化部分声明一个变量,它的作用域为整个for循环。

5).for循环通常用于循环次数确定的情况,但也可以根据循环结束条件完成循环次数不确定的情况。

6).在初始化部分和迭代部分可以使用逗号语句来进行多个操作。逗号语句是用逗号分隔的语句序列。例如:

for(int i = 0, j = 10; i < j; i++, j--){
    ...
}

7).初始化,终止以及迭代部分都可以为空语句(但分号不能省略),逻辑表达式为空时,默认表达式为恒真。可以用下列for循环表示无限循环:

for( ; ; ){
   ...
}

8).for循环常用于数组各个元素或一个字符串中各个字符的处理。

PS:for-each语句

  • for-each语句是for语句的增强版,简化了代码,提高了代码的可读性和安全性(数组越界)。但for-each并不能替代for循环。任何for-each都能改写为for循环,反之不行。
  • for-each语句可用于依次遍历数组或集合中的每一个元素,而不必考虑指定下标值(不考虑从哪开始,从哪结束,不考虑数组越界问题)。如果不想遍历整个数组或集合或者在循环内部需要操作下标值,就要用传统的for循环。
  • for-each语句只可遍历访问输出数组或集合,无法在遍历的过程中对数组或集合进行修改,而for循环可以在遍历的过程中对原数组或集合进行修改。
public class ArrayLearn {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3};
        for (int i : arr) {
            if(i == 1) {
                i = 9;
            }
        }
        System.out.println(arr[1]);
    }
}
//打印2
//改的是临时变量的值,不是数组元素的值

语法格式:

for(元素类型t 元素变量x : 遍历对象A(数组或集合)){
    引用元素变量x的语句;
}

每走一次循环,就将数组的元素依次赋值给临时变量x。

遍历数组:

public static void main(String[] args) {
	String[] demo = {"a", "b", "c"};

	for (String t :demo ) {
		 System.out.println(t);
    }
}

     遍历list集合:

public static void main(String[] args) {
    List<String> list = new ArrayList();
    list.add("a");
    list.add("b");
    list.add("c");

    for(String str : list){
        System.out.println(str);
    }
}

3.循环跳转语句:break和continue

break[label]; //用来从switch语句或循环语句中跳出
continue[label]; //跳过循环体的剩余语句,开始执行下一次循环

这两个语句都可以带标签(label)使用,也可以不带标签使用。

标签是出现在一个语句之前的标识符,标签后面要跟上一个冒号(:),标签定义如下:

label: statement;

3.1.break语句:

让本次循环提前结束(若有多层循环嵌套,就近跳出)。

代码示例:找到100-200中第一个3的倍数

int num = 100;
while(num <= 200){
     if(num % 3 == 0){
         System.out.println("找到了3的倍数,为:" + num);
         break;
     }
     num++;
}
//执行结果
找到了3的倍数,为:102

3.1.1.带标签

带标签的break语句将结束标签所指示的循环的执行。如:它结束了switch语句的执行,并把控制流转移到紧跟在switch之后的语句。

3.1.2.不带标签

不带标签的break语句可以终止循环,用来结束最内层的switch,for,while和do while语句的执行。

3.2.continue语句:

在for,while和do while循环中,continue语句跳过当前循环的其余语句,执行下一次循环,当然执行下次循环前要判定循环条件是否满足。

代码示例:找到100-200中所有3的倍数

int num = 100;
while(num <= 200){
     if(num % 3 != 0){
         num++;
         continue;
     }
     System.out.println("找到了3的倍数,为:" + num);
     num++;
}

3.2.1.带标签

带标签的continue语句结束由标签所指外层循环的当前循环,开始执行该循环的下次循环。

3.2.2.不带标签

不带标签的continue语句跳过最内层的循环,并开始执行最内层循环的下一次循环。

PS:return语句

  • 用return表示当前方法结束调用,当前方法里的后面代码不再执行,有返回值的情况下返回相应的值。继续执行当前方法之后的语句。
  • 在返回类型为void的方法里面,有个隐含的return语句,return可以省略不写。

4.异常处理语句

4.1.捕获异常:try catch finally语句。

4.2.抛出异常:throw语句。

(在异常文章中有详细讲解)
 



 


 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值