SCJP笔记_章五_流程控制、异常与断言

第五章 流程控制、异常与断言 

 

 

5.1 if和switch语句

考试目标2.1 编写实现if或switch语句的代码,并辨别这些语句的合法变元类型。

 

if和switch语句通常被称作判决语句。在程序中使用判决语句时,是在要求程序计算一个给定的表达式,以判断要采取哪个操作。

 

5.1.1 if-else 分支

int a = 10;
if(a>20){
	//doStuff
}else if(a<20){
	//doStuff
}else{
	//doStuff
}

 

if 语句的合法表达式

if语句的唯一合法表达式是布尔表达式。换句话说,只能是可以被解析为布尔值或布尔变量的表达式。

注意布尔赋值(=),它可能被错认为不二相等性(==)测试

public class Test{
	public static void main(String[] args){
		boolean b = true;
		if(b=true){
			System.out.println("b="+b);
		}
	}
}
结果:b=true

 

public class Test{
	public static void main(String[] args){
		boolean b = true;
		if(b=false){
			System.out.println("b="+b);
		}
	}
}
结果:(什么都没有)

 

5.1.2 switch 语句

switch (x) {
	case 1:
		// doStuff
		break;
	case 2:
		// doStuff
		break;
	case 3:
		// doStuff
		break;
	case 4:
		// doStuff
		break;
	default:
		// doStuff
}

 

switch 和 case 的合法表达式

switch(expression){
        case constant1:  code block
        case constant2:  code block
        default:  code block
}

switch的表达式必须能求值成char、byte、short、int或者枚举。这意味着如果没有使用枚举,则只有能够被自动提升为int的变量和值才是可接受的。

case后面的常量必须是字面值或final变量,或者是常量表达式,包括枚举。不能在case中包含非final变量或一个取值范围。

 

switch 块内的中断和直落

case只是这个switch块的入口,如果没有碰到break,它会一直执行下去,直到遇到break,或者switch的尾部。

 

默认 case

default :{}

default case 不一定总要置于switch的末尾。

 

 

5.2 循环和迭代器

考试目标2.2 编写代码,实现循环和迭代器的所有形式,包括使用for、增强型for循环(for-each)、do、while、标签、break和continue,并解释在循环执行期间和执行之后循环计数器变量所具有的值。

 

5.2.1 使用while循环

while (expression) {
    //do stuff
}
//expression应该是一个测试条件,不应将声明放在这里。满足条件执行循环体一次。

 

5.2.2 使用do循环

do{
    //do stuff
}while(expression);
//先执行一次循环体,完成后判断expression的结果,为true则再次执行一次循环体,false则跳出循环

 

5.2.3 使用for循环

旧式的for循环称为“基本for循环”,新式的称之为“增强型for循环”(for-each循环)

 

基本for循环

for循环声明包括3个主要部分:变量的声明和初始化,布尔表达式(条件测试),迭代表达式

 

基本for循环:声明和初始化

for语句的第一部分允许在for关键字之后的圆括号内声明并初始化0个、1个或多个同类型的变量。变量的作用域随着for循环的结束而结束。

for(int x=10,y>3;y>3;y++){}

 

基本for循环:条件(布尔)表达式

只能有一个测试表达式,不能使用逗号分隔的多个测试,但for语句中的另外两个部分可以有多个成分。

for(int x=0;(((x<10)&&(y-->2))|x==3);x++){}

 

基本for循环:迭代表达式

for循环体每次执行之后,都会执行迭代表达式。

除了强制退出之外,for循环中最后做的两件事总是:先计算迭代表达式,然后计算条件表达式。

强制退出包括:break、return、System.exit()方法或者异常。

 

基本for循环:for循环问题

for(;i>10;){}就像一个while(i>10){}

 

增强型for循环(用于数组)

for语句的两个部分是:

声明(declaration)。新声明的块变量,其类型与正在访问的数组元素的类型兼容。

表达式(expression)。它必须计算为想要遍历的数组。

List<Object> aa = new ArrayList<Object>();
for(Object a:aa){
         // do stuff	
}

增强型for循环假定:除非提前退出循环,否则总会遍历数组的每一个元素。

 

5.2.4 使用break和continue

break终止整个循环,continue终止当前的迭代。

 

5.2.5 无标签的语句

“5.2.4”中说的就是无标签的情况

 

5.2.6 带标签的语句

标签要作为所标识的循环的前缀,并在标签名后加“:”。如下:

boolean isTrue = true;
outer:		
for(int i = 0;i<5;i++){
	while(isTrue){
		System.out.println("Hello");
		break outer;
	}
	System.out.println("Outer loop.");
}
System.out.println("Good-Bye");


//结果:
//Hello
//Good-Bye
//可见,如果无标签,break只跳出while,但实际直接跳出了被标记为outer的for循环。

  

 

5.3 处理异常

考试目标2.4 编写使用异常和异常处理子句(try、catch、finally)的代码,并声明抛出异常的方法和重写方法。

考试目标2.5 了解代码段内特定点所产生的异常的后果。注意,异常可以是运行时异常、检验异常或错误。

 

异常语句就是告诉JVM“这些代码可能会出问题,你来监视他,我会告诉你万一出问题了该怎么办”。

异常有两种形式:检验异常和非检验异常。

检验异常包括Exception的所有子类型,但不包括扩展RuntimeException的类。

检验异常遵守处理或声明它的规则,任何可能抛出检验异常的方法(包括调用能够抛出检验异常方法的方法),都必须使用throws关键字声明异常,或者用适当的try/catch处理异常。

Error或RuntimeException的子类型是非检验异常,因此,编译器不强迫要求处理或声明规则。你可以随意声明或处理它们,编译器对此并不关心。

 

5.3.1 使用try和catch捕获异常

5.3.2 使用finally

finally块,只要不是JVM关闭这种情况,则finally块总会运行。

 

try{
                //do stuff
}catch(Exception ex){
	//catch exception
}finally{}

 

5.3.3 传播未捕获的异常

当我们不打算在这里处理异常,可以将异常throw,由下面来处理它。

 

5.3.4 定义异常

异常是一个改变正常程序流程的事件。

当抛出一个异常时,某个特定的Exception子类型的对象被实例化,并作为catch子句的变元传递到异常处理程序。

 

5.3.5 异常层次

Throwable的两个子类型:Exception 和 Error。

应用程序不能从Error恢复,这就谈不上处理。异常表示不是由程序设计错误导致发生的错误,而是由于某个资源不可用,或者正确执行所需的其他某个条件不满足所造成的。

 

5.3.6 处理整个异常类层次

在单个catch子句内可以捕获多种类型的异常。通常我们的异常处理应该是有针对性的,不分情况直接catch Exception的做法是不可取的,最好捕获明确的异常子类型,有针对的处理,编写catch处理代码。

 

5.3.7 异常匹配

最具体的异常处理程序必须总是放在更一般的异常处理程序的上面。

 

5.3.8 异常声明与公共接口

每个方法必须通过提供catch子句处理所有检验异常,或者将每个未处理的检验异常列为一个抛出的异常。

 

5.3.9 重抛同一个异常

在catch子句中可以写 “throw xxx;”这样的语句来重抛同一个异常。

 

 

5.4 常见异常和错误

考试目标2.6 识别将导致以下任何一种异常或错误被抛出的情况:ArrayIndexOutOfBoundsException、ClassCastException、IllegalArgumentException、IllegalStateException、NullPointerException、NumberFormatException、AssertionError、ExceptionInInitializerError、StackOverflowError或者NoClassDefFoundError。理解其中哪些是由虚拟机抛出的,并识别应该以编程方式抛出另外一些异常和错误的情况。

 

异常来自于那里?

  • JVM异常。这些异常或错误由JVM抛出,具有排他性或者最具逻辑性。
  • 程序异常。这些异常由应用程序和/或API程序员显式地抛出。

JVM抛出的异常

以编程方式抛出的异常

考试中的异常和错误小结

常见异常的描述和来源表:

 

异常 描述 通常由谁抛出
ArrayIndexOutOfBoundsException 试图用一个无效索引值(可能为负或者超出了数组的大小)访问数组时抛出 JVM
ClassCastException 试图将一个引用变量强制转换为一个不能通过IS-A测试的类型时抛出 JVM
IllegalArgumentException 当方法接收到的变元格式不同于该方法需要的格式时抛出 以编程方式
IllegalStateException 当环境的状态与正在尝试的操作不匹配时抛出(例如,使用一台已关闭的扫描仪) 以编程方式
NullPointerException 试图访问带有一个当前值为null的引用变量的对象时抛出 JVM
NumberFormatException 一个用于将String转换为数值的方法接收到一个不能转换的String时抛出 以编程方式
AssertionError 当一条语句的布尔测试返回false时抛出 以编程方式
ExceptionInInitializerError 试图初始化静态变量或静态初始化块时抛出 JVM
StackOverflowError 当方法递归层次过深时,通常会抛出这个异常(每次调用都会添加到栈中) JVM
NoClassDefFoundError 由于命令行错误、类路径问题,或者丢失了.class文件,使JVM找不到需要的类时抛出 JVM

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

5.5 使用断言机制

考试目标2.3 编写使用断言的代码,并区分断言的正确使用和错误使用。

 

5.5.1 断言(Assertion)概述

当测试和调试时,你想验证你的假设,但是又不希望在开发完成时去除print语句、运行时异常处理程序或if/else测试。但是将它们保留在程序中至少对向能有所影响。

这时就可以使用断言。它可以在实际部署时被系统自动清除。

 

断言的工作方式:它总是断定某件事情为true,如果不是,则立刻抛出AssertionError异常,告诉你这里跟你想的不一样。

 

断言的两种形式:

//非常简单(really simple)
assert(y>x);

//简单(simple)
assert(y>x):"y is "+y+" x is "+ x;
//这个字符串会被添加到栈踪迹中。

 

断言表达式规则:

public class TestAssert {
	void noReturn(){}
	int aReturn(){return 1;}
	void go(){
		int x = 2;
		boolean b = true;
		
		//合法的
		assert(x==1);					
		assert(b);
		assert true;
		assert(x==1):x;		//第二种表达式“:”后面可以返回的是任何值
		assert(x==1):aReturn();
		assert(x==1):new TestAssert();
		
		//非法的
//		assert(x=1);
//		assert(x);
//		assert 0;
//		assert(x==1):;
//		assert(x==1):noReturn();
//		assert(x==1):TestAssert test;		

	}	
	public static void main(String[] args){
		TestAssert obj = new TestAssert();
		obj.go();
	}
}

 

 

5.5.2 启用断言

 

标识符与关键字

可以将assert用作关键字或者标识符,但是不能同时将它用作这两者。

 

使用java和javac的版本6

 

编译带有断言的代码

javac -source 1.4 JavaObjcet.java

 

带断言运行

默认情况下 断言是禁止的。

 

运行时启用断言

java -ea com.geeksanonymous.TestClass

java -enableassertions com.geeksanonymous.TestClass

 

运行时禁用断言

java -da com.geeksanonymous.TestClass

java -disableassertions com.geeksanonymous.TestClass

 

有选择地启用和禁用

java -ea:com.foo.Bar        在类com.foo.Bar中启用断言

java -ea -da:com.foo.Bar  在除了类com.foo.Bar的其他类中启用断言

java -ea:com.foo...           在包com.foo以及它的任何子类包中启用断言

java -ea -dsa                    通常启动断言,但在系统类中禁止

 

5.5.3 适当地使用断言

 

使用断言验证公共方法的变元

可以使用断言验证私有方法的变元

不要使用断言验证命令行变元

即使在公共方法内,也可以使用断言检查从不会发生的情况

不要使用可能产生副作用的断言表达式

 

你可能感兴趣的:(jvm,游戏,编程,虚拟机,Go)