异常

作者: 爱做梦的严重精神病患者 | 来源:发表于2018-12-19 14:25 被阅读0次

    1.异常

     所有的异常都是由Throwanle继承而来的,但是在下一层立即分解为两个分支ErrorException
    Error类层次结构描述了Java运行时系统的内部错误和资源耗尽错误一般程序运行时不会抛出这种内部错误
    Exception层次结构又分解为两个分支由程序错误导致的异常属于RuntimeException;而程序本身没有问题,但由于像I/O错误这类问题导致的异常属于IOException

     派生于RuntimeException的异常包括下面几种情况:

    • 错误的类型转换
    • 数组访问越界
    • 访问null指针

     如果出现RuntimeException的异常(非受查异常),那么一定是你的问题。

     派生于IOException的异常包括:

    • 试图在文件尾部后面读取数据
    • 试图打开一个不存在的文件
    • 试图根据给定的字符串查找Class对象,而这个字符串表示的类并不存在

     派生于Error类或RuntimeException类的所有异常称为非受查异常,其余的异常(IOException)称为受查异常

    Java异常层次结构.jpg

    2.声明、抛出、捕获异常

    • 声明异常
      一个方法必须声明所有可能抛出的受查异常,而非受查异常要么不可控制(Error),要么就应该避免发生(RuntimeException)
      在方法的首部声明这个方法可能抛出的异常,如果一个方法有可能抛出多个受查异常类型,那么就必须在方法的首部列出所有的异常类。
    class MyAnimation {
      public Image loadImage(String s) throws FileNotFoundException, EOFException {
            ...
          }
    }
    
    • 抛出异常
       假设在程序中的某个逻辑分支,会发生一种不正常的情况,需要我们去抛出异常。(声明异常是在方法的首部,而抛出异常则是在方法的内部)
    String readData(Scanner in) throws EOFException {
            ...
            while(...) {
               if(!in.hasNext()) {
                   if(n < len)
                      throw new EOFException();
                }
            }
    }
    
    • 捕获异常
       当调用了声明或抛出了异常的方法时,需要对异常进行捕获。如果某个异常发生的时候没有在任何地方进行捕获,那么程序就会终止。
      要想捕获一个异常,必须设置try/catch语句块。如果在try语句块中的任何代码抛出了一个在catch子句中说明的异常类,那么程序将跳过try语句块的其余代码,然后程序将执行catch子句中的代码。
    try {
      code
      ...
    } catch(ExceptionType e) {
       handle for this type
    }
    

     通常,我们应该捕获那些知道如何处理的异常,而将那些不知道怎样处理的异常继续进行传递(抛出)

    • 再次抛出异常
       有时抛出的异常需要再次进行包装,在catch子句中可以抛出一个异常,这样做的目的是改变异常的类型。例如开发了一个供其他程序员使用的子系统,那么表示子系统故障的异常类型可能就需要用到包装
    try {
        access the database
    } catch (SQLException e) {
        //  创建一个子系统异常
        Throwable se = new ServeltException("database error");
        se.initCause(e);
        throw se;
    }
    

    这种包装技术可以让用户抛出子系统中的高级异常,而不会丢失原始异常的细节

    • finally子句
       当代码抛出一个异常时,就会终止方法中剩余代码的处理,并退出这个方法的执行。如果方法获取了一些本地资源,那么就会产生资源回收问题。然而,不管是否有异常被捕获,finally子句中的代码都被执行
       对于获取了本地资源的语句,当处理异常时,强烈建议解耦try/catch和try/finally语句块
    InputStream in = ...;
    try {
        try{
            code that might throw exceptions
        } finally {
            in.close();
        }
    } catch (IOException e) {
           show error message
    }
    

    内层的try语句只有一个职责,就是确保关闭输入流外层的try语句块也只有一个职责,就是确保报告出现的错误。这种设计方式不仅清楚,而且还具有一个功能,就是将会报告finally子句中出现的错误。

    • 带资源的try语句
      假设资源属于一个实现了AutoCloseable接口的类Java为这种代码模式提供了一个很有用的快捷方式
      带资源的try语句(try-with-resources)的最简单形式为:
    try(Resource res =...) {
          work with res
    }
    
    try(Scanner in = new Scanner(new FileInputStream("/usr/share/dict/words")), 
    "UTF-8") {
          while(in.hasNext())
                   System.out.println(in.next());
    }
    

    try块退出时,会自动调用res.close(),就好像使用了finally块一样。

    • 早抛出,晚捕获
       很多人都感觉应该捕获抛出的全部异常,其实传递异常比捕获这些异常更好。让高层次的方法通知用户发生了错误,或者放弃不成功的命令更加适宜。

    相关文章

      网友评论

          本文标题:异常

          本文链接:https://www.haomeiwen.com/subject/swuqkqtx.html