7.1 处理错误 - 7.3 使用异常机制的技巧

7.1 处理错误

在出现错误时,用户期望程序能够:

  • 返回到安全状态,并能让用户执行一些其他的命令
  • 允许用户保存所有操作的结果,并以妥善的方式终止程序
    对于方法中的错误,传统做法是返回一个特殊的错误码,由调用方法分析。但是某些时候可能无法明确地将有效数据和错误码加以区分。
异常分类

所有的异常都扩展了 Throwable 类。直接扩展 Throwable 的有两个类 Error 和 Exception。Error 类描述了 Java 运行时系统的内部错误和资源耗尽错误。应用程序不应该抛出这种类型的对象。需要关注的是 Exception 类,Exception 又有两方面扩展 RuntimeException 和其他异常。
如果出现 RuntimeException 一定是编码者的问题。Java 将扩展了 Error 类和 RuntimeException 类的所有异常称为 unchecked 异常,所有其他异常为 checked 异常。编译器将检查是否为所有的受查异常提供了异常处理器。

声明受查异常

声明受查异常在方法声明首部用 throws 声明可能抛出哪类受查异常
不需要声明扩展自 Error 类的错误和扩展自 RuntimeException 的异常,因为非受查异常要么是 Error 不可控制,要么是 RuntimeException 应该避免发生。

如何抛出异常
  1. 找到一个合适的异常类
  2. 创建这个类的一个对象
  3. throw 将对象抛出
创建异常类

自定义一个类扩展自 Exception 类或是 Exception 的子类。习惯上自定义的类应该包括一个默认构造器和一个带详细信息的构造器。

7.2 捕获异常

捕获异常

如果发生异常时没有在任何地方捕获,程序会终止执行并在控制台打印异常信息。
捕获异常需要 try / catch 语句块

try{
    //可能出现异常的代码
}catch (Exception e){
    //处理异常
}

如果 try 语句块中任何代码抛出 catch 子句中声明的异常,将跳过 try 块中的剩余代码,执行 catch 块中的代码。

再次抛出异常与异常链

可以在 catch 块中再次抛出异常,并将原异常包装起来:

try{
    
}catch (SQLException e){
    Throwable se = new ServletException("database error");
    se.initCause(e);//使用se.getCause()就能获得原异常
    throw se;
}

如果在一个方法中发生了受查异常而不允许抛出它,可以将其捕获,并包装成一个 RuntimeException

finally 子句

如果代码获得了一些本地资源,这些资源必须被回收。在回收资源前抛出异常就会导致回收资源的代码没有被执行。使用 finally 子句就能避免这个问题。不论是否有异常被捕获,finally 子句中的代码都将会被执行。

建议

解耦 try / catch 和 try / finally 语句块,内层 try 确保回收资源,外层 try 确保报告抛出的异常,并且还能报告 finally 块中出现的异常。

try{
    try{
        //可能抛出异常的代码
    }finally{
        //必须要做的事,例如回收资源
    }
}catch (Exception e){
    //处理异常
}

方法执行到 return 语句时,finally 中的代码将被执行,如果 finally 中也有 return 语句,这个返回值将覆盖原返回值。

带资源的 try 语句

为了防止资源关闭的过程中抛出异常造成原异常丢失,传统的做法是在 finally 中再使用 try 语句块, 例如

InputStream in = null;  
Exception ex = null;  
try{  
	try{  
        //code…..;  
    } catch (Exception e) {  
        ex = e;  
        throw e;  
    }  
} finally {  
    try {  
        in.close();  
    } catch (Exception e) {  
        if(ex == null)   
         throw e;  
    }  
}  

使用带资源的 try 语句将写成如下形式

try (Scanner sc = new Scanner(new FileInputStream(""))) {      

}

try 括号中可以声明资源,资源需要实现AutoCloseable 类,try 块退出时会自动调用资源实现的 close 方法。

分析堆栈轨迹元素

调用 Throwable 类的 printStackTrace 方法将在控制台输出方法访问堆栈轨迹的文本描述信息。

更灵活的方案是使用 getStackTrace 方法,它会得到 StackTraceElement 对象的一个数组。

7.3 使用异常机制的技巧

  1. 异常处理不能代替简单的测试,与探空,检查null,布尔值判断,数组下标检查等简单的测试相比,捕获异常需要花费大量的时间。因此编码者应该只在异常情况下使用异常
  2. 不要过分细化异常,例如将每句都写在一个 try/catch 块中。
  3. 利用异常层次结构,不要只抛出 RuntimeException ,应当寻找更适当的扩展类或是创建自己的异常类。不要捕获 Throwable 类。
  4. 不要压制异常,
  5. 检测错误时,苛刻更好些,如果后面将会抛出异常,在检查时提交抛出会更好
  6. 不要羞于传递异常,传递异常比直接捕获这些异常通常更好
posted @ 2020-08-23 22:41  PotatoTed  阅读(97)  评论(0)    收藏  举报