异常

  • 异常分为检查时异常 运行时异常 错误

    • 检查时异常如文件不存在等,程序员往往无法预见。而且往往会在编译时被检查出来
    • 运行时异常程序员往往可以避免。但是编译时往往不能检查出来
    • 错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。

      异常类

  • 所有的异常类是从 java.lang.Exception 类继承的子类

  • Java 程序通常不捕获错误Error。错误一般发生在严重故障时,它们在Java程序处理的范畴之外。Error 用来指示运行时环境发生的错误。
    • 例如,JVM 内存溢出。一般地,程序不会从错误中恢复。

image.png

异常捕获

如果方法抛出了异常,那么main调用该方法也需要抛出相应的异常

  1. public static void main(String[] args) throws IOException {
  2. readFile();
  3. }
  4. public static void readFile() throws IOException {
  5. ...
  6. }

try-catch

  • 如果try代码块出现了catch可以捕获的异常,就会执行catch代码块
    • 如果发生的异常包含在 catch 块中,异常会被传递到该 catch 块,这和传递一个参数到方法是一样。
  • 可以一个try捕获多个异常,只需要增加更多的**catch(异常类型 异常变量名){ ... }**
    • try抛出的异常会从第一个catch逐个往下匹配进行捕获
  • try代码块一般写可能异常的代码 catch代码块一般写捕获到异常后的异常处理代码
  • 异常变量可以直接输出,包含异常的信息和异常类型

    try
    {
     // 可能异常的程序代码
    }catch(ExceptionName e1)  //catch()中是一个异常类的对象
    {
     //Catch 块
    }catch(异常类型2 异常的变量名2){
    // 程序代码
    }catch(异常类型3 异常的变量名3){
    // 程序代码
    }  ....
    
    try{
           int a[] = new int[2];
           System.out.println("Access element three :" + a[3]);
        }catch(ArrayIndexOutOfBoundsException e){
           System.out.println("Exception thrown  :" + e);
        }   
    //Exception thrown  :java.lang.ArrayIndexOutOfBoundsException: 3   
    //数组索引出界异常   3表示出错的数组索引为3
    

    throw/throws

  • 如果一个方法可能存在非检查时异常。使用throw或者throws来抛出异常

    • throw抛出一个异常,throws抛出多个异常
    • throw,throws是只抛出异常,不进行处理
  • throw还可以用于在方法抛出异常的方法体中抛出一个异常类对象

    public void deposit(double amount) throw RemoteException
    {
      //方法的实现
      throw new InsufficientFundsException(needs);
    }
    --------------------------------------------
     public void withdraw(double amount) throws RemoteException,
                                InsufficientFundsException
     {
         //方法的实现
     }
    

    finally

  • finally代码块无论是否发生异常都会执行

  • finally写在catch(){}后面 finally{ //代码 }
  • 如果try或者catch中存在return语句,则finally会在return之前执行
    • 不要在finally中写return,貌似是finally会覆盖try中的return,try和catch都有return时不清楚
  • 虚拟机终止运行,finally所在线程死亡等因素会造成finally不一定会被执行

    用法总结

  • catch 不能独立于 try 存在。

  • 在 try/catch 后面添加 finally 块并非强制性要求的。
  • try后面必须有一个catch或者finally。再或者throw/throws抛出异常。
  • try, catch, finally 块之间不能添加任何代码。如**try{...}sout();try{}是错误的**

    public void readFile() throws IOException {
      try (InputStream input = new FileInputStream("src/readme.txt")) {
        ...
            //抛出了个异常,所以可以catch或者finally
      }
    }
    

    try(resource)

  • 这个用法有的地方叫做try-with-resources

  • 平常如果需要关闭资源我们一般会在finally中写下关闭语句。
  • java7中新增了try(resource)功能。在try关键字后增加一对(),将资源创建的语句写在括号中。编译器会自动为我们关闭流

    • 如果有多个资源可以使用;分隔
    • try()中的资源对象如果实现了java.lang.AutoCloseable接口才会自动关闭 编译器会自动加上finally语句并调用close()方法。 如IO流中四大基本接口就实现了自动关闭接口

      public void readFile() throws IOException {
      
      try (InputStream input = new FileInputStream("src/readme.txt")) {
         int n;
         while ((n = input.read()) != -1) {
             System.out.println(n);
         }
      } // 编译器在此自动为我们写入finally并调用close()
      }
      

      异常方法

  • 下面的列表是 Throwable 类的主要方法

  • 异常方法需要异常类对象进行调用,一般用于catch代码块中 | 序号 | 方法及说明 | | —- | —- | | 1 | public String getMessage()
    返回关于发生的异常的详细信息。这个消息在Throwable 类的构造函数中初始化了。 | | 2 | public Throwable getCause()
    返回一个Throwable 对象代表异常原因。 | | 3 | public String toString()
    使用getMessage()的结果返回类的串级名字。 | | 4 | public void printStackTrace()
    打印toString()结果和栈层次到System.err,即错误输出流。 | | 5 | public StackTraceElement [] getStackTrace()
    返回一个包含堆栈层次的数组。下标为0的元素代表栈顶,最后一个元素代表方法调用堆栈的栈底。 | | 6 | public Throwable fillInStackTrace()
    用当前的调用栈层次填充Throwable 对象栈层次,添加到栈层次任何先前信息中。 |

自定义异常

  • 在 Java 中你可以自定义异常。编写自己的异常类时需要记住下面的几点。
    • 所有异常都必须是 Throwable 的子类。
      • throwable有一个detailMessage属性,即异常消息。我们
    • 如果希望写一个检查性异常类,则需要继承 Exception 类。
    • 如果你想写一个运行时异常类,那么需要继承 RuntimeException 类。
  • 不要将异常定义为静态变量。我们应该要使用时重新new一个异常
  • 如果异常执行了打印输出,就不要再进行抛出(规范)
  • 异常抛出与打印等要尽可能地具体,不要直接抛出大范围地,如不要直接抛出Exception

  • 在一个大型项目中,可以自定义新的异常类型,但是,保持一个合理的异常继承体系是非常重要的。
  • 一个常见的做法是自定义一个BaseException作为“根异常”,然后,派生出各种业务类型的异常。
    • BaseException需要从一个适合的Exception派生,通常建议从RuntimeException派生,因为检查性异常一般在代码逻辑上就应该处理
    • 自定义的BaseException应该提供多个构造方法以应对不同情况,其实自定义的异常类的构造方法在父类里都有一模一样的方法可以黏贴
  • 其他业务类型的异常就可以从BaseException派生
    public class BaseException extends RuntimeException {
    }
    
    ```java public class UserNotFoundException extends BaseException { }

public class LoginFailedException extends BaseException { }

```java
public class BaseException extends RuntimeException {
    public BaseException() {
        super();
    }

    public BaseException(String message, Throwable cause) {
        super(message, cause);   //cause是关于内存堆栈的异常信息
    }

    public BaseException(String message) {
        super(message);
    }

    public BaseException(Throwable cause) {
        super(cause);
    }
}

Java 内置异常类-表

  • Java 语言定义了一些异常类在 java.lang 标准包中。
  • 标准运行时异常类的子类是最常见的异常类。由于 java.lang 包是默认加载到所有的 Java 程序的,所以大部分从运行时异常类继承而来的异常都可以直接使用。
  • Java 根据各个类库也定义了一些其他的异常,下面的表中列出了 Java 的非检查性异常。

    运行时异常

    | 异常 | 描述 | | —- | —- | | ArithmeticException | 当出现异常的运算条件时,抛出此异常。例如,一个整数”除以零”时,抛出此类的一个实例。 | | ArrayIndexOutOfBoundsException | 用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引。 | | ArrayStoreException | 试图将错误类型的对象存储到一个对象数组时抛出的异常。 | | ClassCastException | 当试图将对象强制转换为不是实例的子类时,抛出该异常。 | | IllegalArgumentException | 抛出的异常表明向方法传递了一个不合法或不正确的参数。 | | IllegalMonitorStateException | 抛出的异常表明某一线程已经试图等待对象的监视器,或者试图通知其他正在等待对象的监视器而本身没有指定监视器的线程。 | | IllegalStateException | 在非法或不适当的时间调用方法时产生的信号。换句话说,即 Java 环境或 Java 应用程序没有处于请求操作所要求的适当状态下。 | | IllegalThreadStateException | 线程没有处于请求操作所要求的适当状态时抛出的异常。 | | IndexOutOfBoundsException | 指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。 | | NegativeArraySizeException | 如果应用程序试图创建大小为负的数组,则抛出该异常。 | | NullPointerException | 当应用程序试图在需要对象的地方使用 null 时,抛出该异常 | | NumberFormatException | 当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。 | | SecurityException | 由安全管理器抛出的异常,指示存在安全侵犯。 | | StringIndexOutOfBoundsException | 此异常由 String 方法抛出,指示索引或者为负,或者超出字符串的大小。 | | UnsupportedOperationException | 当不支持请求的操作时,抛出该异常。 |

检查时异常

  • 下面的表中列出了 Java 定义在 java.lang 包中的检查性异常类。 | 异常 | 描述 | | —- | —- | | ClassNotFoundException | 应用程序试图加载类时,找不到相应的类,抛出该异常。 | | CloneNotSupportedException | 当调用 Object 类中的 clone 方法克隆对象,但该对象的类无法实现 Cloneable 接口时,抛出该异常。 | | IllegalAccessException | 拒绝访问一个类的时候,抛出该异常。 | | InstantiationException | 当试图使用 Class 类中的 newInstance 方法创建一个类的实例,而指定的类对象因为是一个接口或是一个抽象类而无法实例化时,抛出该异常。 | | InterruptedException | 一个线程被另一个线程中断,抛出该异常。 | | NoSuchFieldException | 请求的变量不存在 | | NoSuchMethodException | 请求的方法不存在 |