《Java核心技术卷1》第七章


异常

传递异常

注意:受查异常必须要声明。受查异常包括IOException 及其子类。

public void read(String filename) throws IOException
{
  ...;
}

捕捉异常

public void read(String filename)
{
    try{
       
    }catch(IOException exception){
         ...;
    }
}

通常, 应该捕获那些知道如何处理的异常, 而将那些不知道怎样处理的异常继续进行传递(传递给用户,让用户去操心)。

注意:不允许在子类的 throws 说明符中出现超过超类方法所列出的异常类范围。

当在try和catch语句外抛出异常,程序会终止。

public class Hello {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[] arr = new int[10];
		int i = -1;
		if (i < 0)
			throw new ArrayIndexOutOfBoundsException();
            //此时程序会终止并抛出一个异常,不会被后面或者上层代码捕捉
		try {
			arr[i] = -1;
		} catch (RuntimeException a) {
			System.out.println("OK");
            //will not print
		}
	}
}

在try语句中抛出异常,继续执行catch子句及之后的代码。

public class Hello {

	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		int[] a = new int[10];
		try {
			throw new ArrayIndexOutOfBoundsException();
		} catch (Exception e) {
			System.out.println("OK");
		}
		System.out.println("YES");
	}
}
//will print OK,YES

在catch语句中抛出异常,异常会被抛回到这个方法的调用者或者外层代码。

捕捉多个异常

try{

}catch(...){

}catch(...){

}catch(...){

}...

更简洁的形式:

try{
   
}catch(FileNotFoundException | UnknownHostException e)

只有当捕获的异常类型彼此之间不存在子类关系时才需要这个特性。

再次抛出异常与异常链

如果 catch 子句抛出了一个异常, 异常将被抛回这个方法的调用者。

使用以下写法可以将底层代码出现的异常抛出给上层,然后抛出一个统一的代码,同时不会丢失最原始的异常信息。

建议使用

public class Hello {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[] arr = new int[10];
		try {
			try {
				arr[-1] = -1;
			} catch (ArrayIndexOutOfBoundsException a) {
				RuntimeException b = new RuntimeException();
				b.initCause(a);
				throw b;
			}
		} catch (RuntimeException a) {
			System.out.println(a.getCause());
		}
	}
}

finally子句

不管是否有异常被捕获,finally 子句中的代码都被执行。

InputStream in = . .
try{
    //code that might throwexceptions
}
finally
{
      in.close();
}
//无论在 try 语句块中是否遇到异常,finally 子句中的 in.close() 语句都会被执行。

在需要关闭资源时, 用这种方式使用 finally 子句是一种不错的选择。

强烈建议解搞合 try/catch 和 try/finally 语句块。这样可以提高代码的清晰度。

例如:

InputStrean in = . . .;
try{
try{
    //code that might throwexceptions
}
finally{
    in.close();
}
}
catch (IOException e){
    show error message
}
//这样写,不仅清楚,而且还可以报告finally子句中出现的错误。

当 finally 子句包含 return 语句时,执行后会覆盖原来原来返回的值。

public class Hello {
	public static int f(int n) {
		try {
			int r = n * n;
			return r;
		} finally {
			if (n == 2)
				return 0;
		}
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println(f(2));
		//will print 0
	}
}

带资源的try语句

try (Resource res = . . .)
{
    work with res
}

try块退出时,会自动调用 res.close()。

断言

断言机制允许在测试期间向代码中插入一些检査语句。当代码发布时,这些插人的检测 语句将会被自动地移走。

什么时候应该选择使用断言呢? 请记住下面几点:

  1. 断言失败是致命的、 不可恢复的错误。

  2. 断言检查只用于开发和测阶段(这种做法有时候被戏称为“ 在靠近海岸时穿上救生衣, 但在海中央时就把救生衣抛掉吧”)。

    因此,不应该使用断言向程序的其他部分通告发生了可恢复性的错误,或者,不应该作 为程序向用户通告问题的手段。断言只应该用于在测试阶段确定程序内部的错误位置;

    assert 条件;
    assert 条件:表达式;
    //结果为false时抛出一个AssertionError异常,表达式将被传入AssertionError构造器,并转换成一个消息字符串

文章作者: 淡夜
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 淡夜 !
评论
  目录