块和语句

hardwork
总结所有流程控制和注意的点

前面的话

此文的编写参考了较多经典文献:《Java Rules》、《Java Language Specification 7》、《Java Virtual Machine Specification 7》、《Core Java》、《Java JDK8学习笔记》等,所以比较权威,不过鄙人才疏学浅,出错在所难免,望指出。

块(block)

块是指放在大括号中的一连串语句、局部类声明和局部变量声明语句。
块确定了变量的作用域。一个块可以嵌套在另一个块中。
一个块可以嵌套在另一个块中。下面是main方法中嵌套另一个语句块的示例:

public static void main(String[] args)
{
    int n;
    ...
    {
        int k;
        ...
    }    // k is noly defined up to here
}

但是,不能在嵌套的两个块中声明相同的变量。例如,下面代码无法通过编译:

public static void main(String[] args)
{
    int n;
    ...
    {
        int k;
        ...
        int n;    // Error--can't redefine n in inner block
    }
}

在C++中,可以在嵌套的块中定义一个变量。在内层定义的变量会覆盖外层定义的变量。这样,有可能会导致程序设计错误,在Java中不被允许。

块是从上到下,从左到右执行每个局部变量声明和其它语句的。如果所有块语句正常结束,那么块就正常结束。如果出于任何原因,这些块的任何语句突然结束,那么块就出于相同原因突然结束。

突然结束总有一个相关的原因,为下列原因之一:

  • 无给定标签的break
  • 有给定标签的break
  • 无给定标签的continue
  • 有给定标签的continue
  • 无值的return
  • 有值的return
  • 具有指定值的throw,包括JVM抛出的异常

局部类声明(Local Class Declarations)

局部类是一个嵌套类,该嵌套类不是任何一个类的成员,并且具有一个名称。JLS原文:a local class is a nested class that is not a member of any class and that has a name

所有的局部类都是内部类。

所有局部类的声明语句直接包含于块中,并且可以和其它语句一起出现在块中。JLS原文:every local class declaration statement is immediately contained by a block. Local class declaration statements may be intermixed freely with other kinds of statement in the block

如果局部类声明包含下面访问修饰符的任何之一,那么它就是一个编译时错误:public 、 protected 、 private 或 static 。

下面是上面给出的规则的几个方面的示例:

class Global {
    class Cyclic {}
    void foo() {
        new Cyclic();    // create a Global.Cyclic
        class Cyclic extends Cyclic {}; //circular definition

        {
            class Local {};
            {
                class Local {};    //compile-time error
            }
            class Local {};    //complile-time error
            class AnotherLocal {
                void bar() {
                    class Local {}    // ok
                }
            }
        }
        class Local {}    // ok, not in scope of prior Local
    }    
}

方法foo的第一条语句创建了成员类Global.Cyclic的一个实例,而不是创建局部类Cyclic的一个实例,因为局部类声明仍不在此作用域中。

局部类作用域包含它自己的声明(而不是它的体)意味着局部类Cyclic的定义确实是循环的,因为它扩展了自身,而不是扩展了Global.Cyclic。因此,局部类Cyclic的声明将在编译时被拒绝。

由于局部类名称不能在相同的方法(或构造函数或初始化等其它可能的情况)重新进行声明,所以Local 的第二和第三个声明导致了编译时错误。但Local可以在另一个(更加深层嵌套的)类(比如AnotherLocal)的上下文中进行重新声明。

Local的第4个和最后一个声明是合法的,因此它在Local任何之前声明的作用域之外发生。

*Tips:看了这么久我猜你也没怎么看懂,其实说的就是局部内部类*

局部变量声明和作用域

这一部分在Java语言规范中讲的晦涩难懂,如果想了解这一部分可以看如下博客:

Java变量作用域和堆栈

语句(Statement)

空语句(Empty Statement)

一条空语句将什么都不做,语法为一个分号;

空语句的执行始终正常完成。

标签语句(Labeled Statement)

Java没有C/C++的goto语句,goto作为保留字存在。

标签语句时和break或continue语句一起使用的,这些语句出现在标签语句中的任何地方。

如果语句是通过Identifier加标签的,并且包含的Statement由于具有相同Identifier的break突然结束,那么标签语句就突然结束,在Statement的所有其它突然结束的情形中,标签语句出于相同原因突然结束。

break with label:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Test {
public static void main(String[] args) {
back:
{
for (int i = 0; i < 10; i++) {
if (i == 9) {
System.out.println("break");
break back;
}
}
System.out.println("test");
}
}
}

程序执行结果会显示break

continue with label:

1
2
3
4
5
6
7
8
9
10
11
12
class Test {
public static void main(String[] args) {
back1:
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
if (j == 9) {
continue back1;
}
}
}
}
}

continue配套标签的使用时,标签只能在循环内部,否则会出现编译错误。

表达式语句(Expression Statement)

某些类别的表达式通过在它们后面加个分号可以用作语句:
ExpressionStatement:
StatementExpression;

StatementExpression:

  • Assignment
  • PreIncrementExpression
  • PreDecrementExpression
  • PostIncrementExpression
  • PostDecrementExpression
  • MethodInvocation
  • ClassInstanceCreationExpression

表达式语句时通过求表达式的值执行的:如果表达式具有一个值,那么该值就被丢弃。当且仅当表达式的求值正常结束时,表达式语句的执行才正常结束。

if语句(If Then [else] Statement)

语法格式:

if (condition) statement

与绝大多数程序设计语言一样,Java希望在某个条件为真时执行多条语句。在这种情况下,应该使用块语句(block statement)。

使用块(有时称为复合语句)可以在Java程序结构中原本只能放置一条简单语句的地方放置多条语句。Java中,常见的语句格式如下:

if (condition) {
    statement1
}
else {
    statement2
}
//condition必须具有boolean或Boolean类型,否则会出现编译错误

Tips

Apple 曾提交一个IOS上的安全更新:http://support.apple.com/kb/HT6147。原因是在某个函式中有两个连续的缩排:

...
if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
    goto fail;
    goto fail;    // always do
if ((err = SSLHashSHA1.final(&hashCtx, &signedParams)) != 0)
    goto fail;
...
因为缩排在同一层,阅读代码时大概没有注意到,又没有定义块,结果会出现goto fail无论如何都会被执行的错误。

所以在写if…else语句时,可读性是应当被重视的一件事。在编写条件控制语句时,首先要做的是理清思路再写代码。

assert语句(Assert Statement)

由于JLS讲的太不亲民了,所以推荐别人写的优秀的博客

深入解析Java Assertion

switch语句(Switch Statement)

在Java7以前,switch可用于比较整数、字符、Enum,Java7以后增加了字符串的比较。语法如下:

switch (变量或布尔表达式)
{
    case 整数、字符、枚举或字符串
        ...
        break;
    ...
    default:
        ...
}

while语句(While Statement)

while (变量或布尔表达式){
    ...
}

do语句(Do Statement)

do {
    ...
} while (变量或布尔表达式)

for语句(For Statement)

基本for循环(BasicForStatement):

for (ForInit; Expression; ForUpdate) Statement

增强for循环(EnhancedForStatement):

for (VariableModifiers Type Identifier : Expression) Statement

break语句(Break Statement)

continue语句(Continue Statement)

throw语句(Throw Statement)

synchronized语句(Synchronized Statement)

try语句(Try Statement)

不可到达语句

坚持原创技术分享,您的支持将鼓励我继续创作