004_JAVA 的流程控制和数组

Rambo 2020年05月25日 271次浏览

一、流程控制

  无论哪一种编程语言,都会提供两种基本的流程控制结构:分支结构和循环结构,Java也提供了ifswitch两种分支结构,并提供了whiledo whileforforeach(JDK1.5以后提出的)的循环结构。foreach循环,能以更简单的方式来遍历集合、数组的元素,除此之外java还提供了breakcontinue来控制程序的循环结构。

顺序结构

  这是编程语言中最常见的程序结构。顺序结构就是程序从上到下逐行执行,中间没有任何判断和跳转。

分支结构

  java常见的两种分支结构if语句和switch语句,其中if语句使用布尔表达式布尔值作为分支条件来进行分支控制。而switch语句则用于对多个整型值进行匹配,从而实现多分支控制。

if 语句语法

// 形式一
if(布尔表达式或布尔值) {
    // 一条或多条可执行语句
}

// 形式二
if(布尔表达式或布尔值) {
    // 一条或多条可执行语句
}
else {
    // 一条或多条可执行语句
}

// 形式三
if(布尔表达式或布尔值) {
    // 一条或多条可执行语句
}
else if(布尔表达式或布尔值) {
    // 一条或多条可执行语句
}
...
else {
    // 一条或多条可执行语句
}

switch 语句语法
  switch语句由一个控制表达式和多个case标签组成,和if语句不同的是,switch语句后面的控制表达式的数据类型只能是整型或者字符串,不能使boolean型。case标签后紧跟一个代码块,case标签作为这个代码块的标志。

switch (整型表达式或字符串) {
    case 条件一: // case代码块的花括号是可以省略的 
    {
        // 一条或多条可执行语句
        break;
    }
    case 条件二:
    {
        // 一条或多条可执行语句
        break;
    }
    default:
    {
        // 一条或多条可执行语句
        break; // 如果default在最后可以省略此break;
    }
}

P.S
  switchif语句不同的是,switch语句中各case标签前后代码块的开始点和结束点非常的清晰,因此完全可以省略case后代码块的花括号。

  switch语句有两个值得注意的地方:第一个地方时switch语句括号内表达式的数据类型只能是bytecharshortint类型和String类型。第二个不同地方时如果省略了case后面的break时,所引入的陷阱(一旦遇到相等的值,程序就开始执行这个case对应标签代码块,不再判断以后的casedefault标签中的条件是否匹配,除非遇到了break才会结束)。

循环结构
// 形式一
while(true / false) {
    // 循环体
}

// 形式二
do {
    // 循环体
}
while(true /false); // 注意这个分号是不可以省略的

// 形式三
for(表达式1、表达式2、表达式3) {
    // 循环体
}

嵌套循环
  如果把一个循环放在另一个循环的内部,那么就可以形成嵌套循环,各种类型的循环都可以作为内循环,各种类型的循环都可以作为外循环。
  当程序遇到嵌套循环时,如果外循环的条件允许,则开始执行外循环的循环体,而内层循环将被外层循环的循环体来执行 —— 只是内层循环需要反复执行自己的循环体而已。
  实际上,嵌套循环不仅可以是两层嵌套,也可以是三层、四层......不论循环如何嵌套,我们都可以把内层循环当成外层循环的循环体来对待,区别只是这个循环体里包含了需要反复执行的代码。

控制循环结构
  java语言没有提供goto语句来控制程序的跳转,这种做法提高了程序流程控制的可读性,但是降低了程序流程控制的灵活性。为了弥补这种不足,java提供了continuebreak来控制循环结构。除此之外,return可以结束整个方法,当然也就是结束了一次循环。

使用break结束循环
  在某些时候,我们需要在某种条件出现时,强制终止结束循环,而不是等待循环条件为false时才结束循环。此时可以使用break来完成这个功能。break用于完全结束一个循环,跳出循环体。不管是哪种循环,一旦在循环体重遇到了break,系统将完全结束该循环,开始执行循环之后的代码。
  break不仅可以结束其所在的循环,还可以直接结束其外层循环,此时需要在break后紧跟一个标签,这个标签用于标识一个外层循环。
  break中的标签就是一个紧跟英文冒号(:)标识符,与其他语言不同的是java中的标签只有放在循环语句之前才有作用

P.S
紧跟break之后的标签,必须在break所在循环的外层循环之前定义才有意义。

public static void main(String args[]) {
    for (int i = 0; i < 5; i++) {
        System.out.println("i=" + i);
        if (i == 3) {
            break;
            // 当i恒等于3的时候,就跳出整个循环体,执行循环后面的代码
        }
    }
    System.out.println("我知道i==3,因为在循环体中当i==3时,利用break语句将循环体强制结束了!!!");


    int j;
    int k;
    Loop:
    for (j = 0; j < 5; j++) {
        for (k = 0; k < 3; k++) {
            System.out.println("j=" + j + " , k=" + k);
            if (k == 2) {
                //break;
                // 当k==2时,强制结束内层循环,再开始外层循环
                break Loop;
            }
        }
    }
    System.out.println("当内层循环k==2时,break Loop 结束标签Loop所在的外层循环!!!");
}

使用continue结束本次循环
  continue的功能和break有点类似,区别是continue只是中止本次循环,接着开始下一次循环。而break则是完全终止循环体。可以理解为continue的作用是略过当次循环中剩下的语句,重新开始新的循环。
  如果将continue放到循环体的最后一行,显然不会有任何意义。
  与break相似,continue也可以紧跟一个标签,用于直接结束标签所标识的当次循环,重新开始下一次循环。

public static void main(String args[]) {
    for (int i = 0; i < 5; i++) {
        System.out.println("i = " + i);
        if (i == 2) {
            // 当 i==2时,结束本次循环,开始下一次循环
            continue;
        }
        System.out.println("continue后的输出语句!");
    }

    Loop:
    for (int j = 0; j < 5; j++) {
        for (int k = 0; k < 4; k++) {
            if (k == 2) {
                continue Loop;
            }
            System.out.println("j = " + j + ", k= " + k);
        }
    }

    String str = "";
    for (int i = 0; i < 15; i++) {
        for (int j = 15; j > i; j--) {
            str += " ";
        }
        for (int j = 0; j < i; j++) {
            str += "* ";
        }
        str += "\n";
    }
    System.out.print(str);
}

使用return结束方法
  return关键字不是专门用于跳出循环的,return的功能是结束一个方法。当一个方法执行到一个return语句时,(return关键字后面还可以跟变量、常量和表达式)这个方法将被结束。
  java程序中大部分的循环都被放在方法中执行,如果return关键字出现在循环中,整个方法都结束了,也显然循环结束了。

二、数组

  数组也是大部分编程语言都支持的数据结构,java也是如此。java的数组类型是一种引用类型的变量,java程序通过数组的引用变量来操作数组,包括获取数组的长度,访问数组的元素值等。

数组类型

  数组是编程语言中最常见的一种数据结构,它用于存储多个数据,一个数据被称为数组中的一个元素,通常可以通过数组的索引来访问数组的元素,包括为数组元素赋值和取出数组元素的数据。

理解数组

数组也是一种类型

  java的数组要求所有的数组元素都具有相同的类型。因此,在一个数组中,数组元素的类型是唯一的,即一个数组里只能存储一种数据类型的数据,而不能存储多种数据类型的数据。

  一旦数组初始化完成,数组在内存中所占的空间就被固定下来,因此数组的长度将不可改变。即使把某个数组元素的数据清空,但它所占的内存空间依然被保留,依然属于该数组,数组的长度依然不变。

  java的数组既可以存储基本数据类型的数据,也可以存储引用数据类型的数据。只要所有数组元素的类型相同即可。

  值得指出的是:数组也是一种数据类型,它本身是一种引用类型。如 int是一个基本类型,但是 int[](这是定义数组的一种方式)就是一种引用类型了。

  类似int[]这种类型也是一种数据类型,与int类型、String类型类似,一样可以使用该类型来定义变量,也可以使用该类型进行类型转换等,使用int[]类型来定义变量和进行类型转换时与使用其他普通类型没有任何区别。int[]类型是一种引用类型,创建int[]类型的对象时也就是创建数组,则需要使用创建数组的语言。

定义数组

java语言支持两种语法格式来定义数组:

type[] arrayName; //建议使用这种,有语义感和可读性
type arrayName[];

对于以上两种定义格式而言,通常推荐使用第一种格式,因为第一种格式不仅具有更好的语意,而且具有更好的可读性。

很多语言已经不再支持type arryName[]这种语法了,比如C#,它只支持第一种定义格式。

  数组是一种引用类型的变量,因此使用它定义一个变量时,仅仅表示定义了一个引用变量(也就是定义了一个指针),这个引用变量还未指向任何有效的内存,因此定义数组时不能指定数组的长度。而且由于定义数组仅仅只是定义了一个引用变量,并未指向任何的有效内存空间,所以还没有内存空间来存储数组元素,因此这个数组也不能使用,只有对数组初始化时指定长度并初始化后才可以使用。

数组的初始化

  java语言中的数组必须先初始化才可以使用,所谓初始化就是为数组元素分配内存空间,并为每个数组元素赋初值。

  一旦为数组的每个数组元素分配了内存空间,每个内存空间里面存储的内容就是该数组元素的值,即使这个内存空间存储的内容是空,这个空也是一个值(null)。不管以哪种方式来初始化数组,只要为数组元素分配了内存空间,数组元素就具有了初始值,初始值的获取有两种形式:一种是系统自动分配,一种是程序员指定。

数组的初始化有两种方式

  • 静态初始化
    初始化时由程序员显式指定每个数组元素的初始值,由系统决定需要的数组长度

    type[] arrayName = new type[]{element1 , element2 , element3 ,......};
    OR  
    type[] arrayName = {element1 , element2 , element3 ,......};
    
  • 动态初始化
    初始化时程序员指定数组长度,由系统为数组元素分配初始值

    type[] arrayName = new type[10];
    

  前面的 type就是数组元素的数据类型,此处的type必须与定义数组变量时所使用的type类型相同,也可以是定义数组时所使用的type的子类。并使用花括号把所有的数组元素括起来,多个数组元素之间用逗号(,)隔开,定义初始化值的花括号紧跟[]之后。值得指出的是:执行静态初始化时,显式指定的数组元素值的类型必须与new关键字之后的type类型相同,或者是其子类的实例。