重温Java(四):控制流程

本章目录
1.控制流程
2.语句块
3.方法
4.方法重载(overload)
5.递归结构

1.控制流程

本章开始我们需要学习流程控制语句,流程控制语句是用来控制程序中各语句执行顺序的语句,可以把语句组合成能完成一定功能的小逻辑模块。控制语句分为三类:顺序、选择和循环。

  • “顺序结构”代表“先执行a,再执行b”的逻辑。比如,先找个女朋友,再给女朋友打电话;先订婚,再结婚;
  • “选择结构”代表“如果…,则…”的逻辑。比如,如果女朋友来电,则迅速接电话;如果看到红灯,则停车;
  • “循环结构”代表“如果…,则再继续…”的逻辑。比如,如果没打通女朋友电话,则再继续打一次; 如果没找到喜欢的人,则再继续找。

这三种基本逻辑结构是相互支撑的,它们共同构成了算法的基本结构,无论怎样复杂的逻辑结构,都可以通过它们来表达。上述两种结构组成的程序可以解决全部的问题,所以任何一种高级语言都具备上述两种结构。

1.1 选择结构

选择结构用于判断给定的条件,然后根据判断的结果来控制程序的流程。

主要的选择结构有:if选择结构和switch多选择结构。有如下结构:

  • if单选择结构
  • if-else双选择结构
  • if-else if-else多选择结构
  • switch结构
1.1.1 if-then 单选泽结构

语法格式:

if (condition) {
	block statement;
}

这里的条件必须使用括号括起来,if语句会对condition进行一次判定,若结果为真则执行{}中的语句块,否则跳过该语句块。流程图如下:
if单选择结构流程图
示例:

public static void main(String[] args) {
    // 通过掷骰子看看今天手气如何
    int i = (int)(6 * Math.random()) + 1;
    int j = (int)(6 * Math.random()) + 1;
    int k = (int)(6 * Math.random()) + 1;

    int count = i + j + k;
    // 如果三个骰子之和大于15,则手气不错
    if (count > 15) {
        System.out.println("今天手气不错");
    }

    // 如果三个骰子之和在10到15之间,则手气一般
    if (count >= 10 && count <= 15) {
        System.out.println("今天手气一般");
    }

    // 如果三个骰子之和小于10,则手气不怎么样
    if (count < 10) {
        System.out.println("今天手气不怎么样");
    }
    System.out.println("得了" + count + "分");
}

注意:如果if语句不写{},则只能作用于后面第一条语句;强烈建议,任何时候if语句后面都写上{},即使语句块中只有一条语句。

1.1.2 if-then-else双选择结构

语法格式:

if (condition) {
	block statement1;
} else {
	block statement2;
}

当判断条件为真时,执行语句块1,否则执行语句块2,也就是else部分。流程图如下:
 if-else双选择结构流程图

注意:else子句与最邻近的if语句构成一组。因此,在语句

if (x <= 0) if (x == 0)  y = 0; else y = -1;

其中else与第二个if配对。当然,使用括号将会使代码更加清晰

if (x <= 0) {
    if (x == 0) {
        y = 0;
    } else {
        y = -1;
    }
}

示例

public static void main(String[] args) {
    double r = 4 * Math.random();
    double area = Math.PI * Math.pow(r, 2);
    double circle = 2 * Math.PI * r;
    System.out.println("半径为:" + r);
    System.out.println("面积为: " + area);
    System.out.println("周长为: " + circle);
    if(area >= circle) {
        System.out.println("面积大于等于周长");
    } else {
        System.out.println("周长大于面积");
    }
}
1.1.3 if-else if-else多选择结构

语法格式:

if (condition1) {
	block statement1;
} else if (condition2) {
	block statement2;
} else {
	block statement3;
}

当条件1为真,执行语句1;否则继续判断条件2,当条件2为真时,则执行语句2;否则执行语句3。如果还有更多的条件,以此类推,流程图如下:
if-else if-else多选择结构流程图

示例:

public static void main(String[] args) {
    int age = (int) (100 * Math.random());
    System.out.print("年龄是" + age + ", 属于");
    if (age < 15) {
        System.out.println("儿童, 喜欢玩!");
    } else if (age < 25) {
        System.out.println("青年, 要学习!");
    } else if (age < 45) {
        System.out.println("中年, 要工作!");
    } else if (age < 65) {
        System.out.println("中老年, 要补钙!");
    } else if (age < 85) {
        System.out.println("老年, 多运动!");
    } else {
        System.out.println("老寿星, 古来稀!");
    }
}
1.1.4 多重选择:switch多分支选择结构

根据表达式值的不同执行许多不同的操作。
语法格式

switch (condition) {
	case value1:
		statement1;
		[break;]
	case value2:
		statement2;
		[break;]
		……
	[default: default statement;]
}

流程图:
switch多选择结构流程图

  1. switch语句会根据表达式的值从相匹配的case标签处开始执行,一直执行到break标签处或者是switch语句的末尾。如果没有相匹配的case标签,则进入default语句(如果有的话)
  2. 只能处理等值条件判断的情况,且case标签的类型必须为byte,short,int或char的常量表达式、枚举常量、从JavaSE 7 开始,case标签可以是字符串面量。注意,还可以是Character, Byte, Short 和 Integer(具体参考Java官网教程
  3. 常量值必须是与表达式类型兼容的特定的一个常量
  4. 不允许有重复的case值
  5. default子句为可选

示例:

public static void main(String[] args) {
    char c = 'a';
    int rand =(int) (26 * Math.random());
    char c2 = (char)(c + rand);
    System.out.print(c2 + ":");
    switch (c2) {
        case 'a':
        case 'e':
        case 'i':
        case 'o':
        case 'u':
            System.out.println("元音");
            break;
        case 'y':
        case 'w':
            System.out.println("半元音");
            break;
        default:
            System.out.println("辅音");
    }
}
1.2 循环结构

循环结构分两大类,一类是当型,一类是直到型。

  • 当型:
    当布尔表达式条件为true时,反复执行某语句,当布尔表达式的值为false时才停止循环,比如:while与for循环。
  • 直到型:
    先执行某语句, 再判断布尔表达式,如果为true,再执行某语句,如此反复,直到布尔表达式条件为false时才停止循环,比如do-while循环。
1.2.1 while循环

语法格式:

while (condition) {
	statement;
}

在循环开始时,会计算一次判断条件的值,若条件为真,则执行循环体;而对于后来每一次额外的循环,都会在开始前重新计算一次判断条件,满足条件则继续执行循环体,否则结束。流程图:
 while流程图
示例:

public static void main(String[] args) {
    int i = 0;
    int sum = 0;
    while (i <= 100) {
        sum += i; //sum = sum+i;
        i++;
    }
    System.out.println("Sum = " + sum);
}

通过while可以实现无限循环

while (true){
    // your code goes here
}
1.2.2 do-while 循环

语法格式:

do {
	statement;
} while (condition);

do-while循环结构会先执行循环体,然后判断条件;若条件为真,执行循环体,当条件为假时结束循环。do-while循环的循环体至少执行一次。do-while循环结构流程图:
do-while流程图

总结:do-while循环是先执行后判断;while循环是判断,后执行;do-while循环保证循环体至少执行一次。

1.2.3 for循环

语法格式:

for(初始化表达式; 布尔表达式; 迭代因子) {
	statement;
}

for循环语句是支持迭代的一种通用结构,是最有效、最灵活的循环结构,流程图:
for循环流程图

示例:

public static void main(String[] args) {
    int sum = 0;
    for (int i = 0; i <= 100; i++) {
        sum += i;
    }
    System.out.println("Sum = " + sum);
}

注意事项

  • for循环在执行条件测试后,先执行程序部分,再执行步进即迭代因子。
  • 在for语句的初始化部分声明的变量,其作用域为整个for循环体
  • “初始化”和“循环条件表达式”部分可以使用逗号来执行多个操作
  • 如果三个部分都为空语句(分号不能省),相当于一个无限循环
public static void main(String[] args) {
    for (;;) { // 无限循环,相当于while(true)
        System.out.println("Java");
    }
}

编译器将while(true)与for(;;)看作同一回事,都指的是无限循环。

在一个循环语句中再嵌套一个或多个循环,称为嵌套循环。例如:

public static void main(String[] args) {
    for (int i = 0; i <= 5; i++) {
        for (int j = 0; j < 5; j++) {
            System.out.print(i + " ");
        }
        System.out.println();
    }
}

嵌套循环实现九九乘法表

public static void main(String[] args) {
    for (int i = 1; i < 10; i++) {
        for (int j = 1; j <= i; j++) {
            System.out.print(j + " * " + i + " = " + (i * j < 10 ? (" " + i * j) : i * j) + " ");
        }
        System.out.println();
    }
}
1.3 分支语句

break语句和continue语句

  • 在任何循环语句的主体部分,均可用break控制循环的流程。break用于强行退出循环,不再执行循环中剩余的语句。(break语句还可用于多支语句switch中)
  • continue 语句用在循环语句体中,用于终止某次循环过程,即跳过循环体中尚未执行的语句,接着进行下一次是否执行循环的判定。

示例
break语句

public static void main(String[] args) {
    int total = 0;
    System.out.println("Begin");
    while(true) {
        total++;
        int i = (int)Math.round(100 * Math.random());
        if(i == 88) break;
    }
    System.out.println("Game over, used " + total + " times.");
}

continue语句

public static void main(String[] args) {
    int count = 0;
    for (int i = 100; i < 150; i++) {
        if (i % 3 == 0) {
            continue;
        }
        System.out.print(i + " ");
        count++;
        if (count % 5 == 0) {
            System.out.println();
        }
    }
}

return语句
最后一个分支语句是return语句。返回语句退出当前方法,控制流返回到调用该方法的位置。return语句有两种形式:一种是返回值,另一种是不返回值。要返回值,只需将值(或计算值的表达式)放在return关键字之后。
例如:

return ++count;

返回值的数据类型必须与方法声明的返回值的类型匹配。当方法被声明为void时,请使用不返回值的返回形式。
例如:

return
2.语句块

语句块(有时叫做复合语句),是大括号之间的一组零个或多个语句,可以在任何允许使用单个语句的地方使用。

  • 块确定了局部变量的作用域。
  • 块中的程序代码,作为一个整体,是要被一起执行的。
  • 块可以被嵌套在另一个块中,但是不能在两个嵌套的块内声明同名的变量。
  • 语句块可以使用外部的变量,而外部不能使用语句块中定义的变量,因为语句块中定义的变量作用域只限于语句块。

示例

class BlockDemo {
     public static void main(String[] args) {
          boolean condition = true;
          if (condition) { // begin block 1
               System.out.println("Condition is true.");
          } // end block one
          else { // begin block 2
               System.out.println("Condition is false.");
          } // end block 2
     }
}
3.方法

方法就是一段用来完成特定功能的代码片段,类似于其它语言的函数。

  • 方法用于定义该类或该类的实例的行为特征和功能实现。
  • 方法是类和对象行为特征的抽象。
  • 方法很类似于面向过程中的函数。面向过程中,函数是最基本单位,整个程序由一个个函数调用组成。面向对象中,整个程序的基本单位是类,方法是从属于类和对象的。

方法的格式

[修饰符] 方法返回值类型 方法名(形参列表) {
	Java语句;
	[return 返回值;]
}

方法的调用方式:

对象名.方法名(实参列表)

方法的详细说明:

  1. 形式参数:在方法声明时用于接收外界传入的数据。
  2. 实参:调用方法时实际传给方法的数据。
  3. 返回值:方法在执行完毕后返回给调用它的环境的数据。
  4. 返回值类型:事先约定的返回值的数据类型,如无返回值,必行在方法声明中显示指定为void

注意事项:

  1. 实参的数目、数据类型和次序必须和所调用的方法声明的形式参数列表匹配。
  2. return语句终止方法的运行并指定要返回的数据。
  3. Java中进行方法调用中传递参数时,遵循值传递的原则(传递的都是数据的副本)。
  4. 基本数据类型传递的是该数据的copy值。
  5. 引用类型传递的是该对象引用的copy值,但指向的是同一个对象。
4.方法重载(overload)

方法的重载是指一个类中可以定义多个方法名相同,但参数不同的方法。 调用时,会根据不同的参数自动匹配对应的方法。

构成方法重载的条件:

  1. 不同含义:形参类型、形参个数、形参顺序不同
  2. 只有返回值不同不构成方法的重载
  3. 只有形参的名称不同,不构成方法的重载

如:以下返回值不同,所以不构成方法重载

int a(String string) {}void a(String string) {}

如:以下形参名称不同,所以不构成方法重载

int a(String str1) {}int a(String str2) {}

方法重载示例:

public static int add(int n1, int n2) {
    return n1 + n2;
}

// 方法名相同,参数个数不同,构成重载
public static int add(int n1, int n2, int n3) {
    return n1 + n2 + n3;
}

// 方法名相同,参数类型不同,构成重载
public static double add(double n1, int n2) {
    return n1 + n2;
}

// 方法名相同,参数顺序不同,构成重载
public static double add(int n1, double n2) {
    return n1 + n2;
}
5.递归结构

递归是一种常见的解决问题的方法,即把问题逐渐简单化。递归的基本思想就是“自己调用自己”,一个使用递归技术的方法将会直接或者间接的调用自己。

利用递归可以用简单的程序来解决一些复杂的问题。比如:斐波那契数列的计算、汉诺塔、快排等问题。

递归结构包括两个部分:

  1. 定义递归头。解答:什么时候不调用自身方法。如果没有头,将陷入死循环,也就是递归的结束条件。
  2. 递归体。解答:什么时候需要调用自身方法。

递归示例:

public class Test22 {
    public static void main(String[] args) {
        long d1 = System.currentTimeMillis();  
        System.out.printf("%d阶乘的结果:%s%n", 10, factorial(10));
        long d2 = System.currentTimeMillis();
        System.out.printf("递归费时:%s%n", d2-d1);  //耗时:32ms
    }
    /** 求阶乘的方法*/
    static long  factorial(int n){
        if(n==1){//递归头
            return 1;
        }else{//递归体
            return n*factorial(n-1);//n! = n * (n-1)!
        }
    }
}

递归的缺陷
简单的程序是递归的优点之一。但是递归调用会占用大量的系统堆栈,内存耗用多,在递归调用层次多时速度要比循环慢的多,所以在使用递归时要慎重。

注意事项
任何能用递归解决的问题也能使用迭代解决。当递归方法可以更加自然地反映问题,并且易于理解和调试,并且不强调效率问题时,可以采用递归;

在要求高性能的情况下尽量避免使用递归,递归调用既花时间又耗内存。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值