Java异常体系总结

219 阅读5分钟

这是我参与2022首次更文挑战的第9天,活动详情查看:2022首次更文挑战

异常体系图

在这里插入图片描述

Throwable是所有异常的父类,它有错误(Error)和异常(Exception)两个子类,下面对他们进行一个解释。

Error

Error往往是很严重的错误,是程序无法处理的异常,我们没办法通过程序进行捕获,比如内存溢出(OutOfMemoryError)、线程死亡(ThreadDeath),java虚拟机运行错误(Virtual MachineError)等。这些异常发生时, Java虚拟机(JVM)一般会选择线程终止。 这类错误只能我们自己改正回来,举个例子:

import java.util.ArrayList;
import java.util.List;

/*设置java堆的大小为20M -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError*/

public class Demo06 {
    static class OOMObject{

    }
    public static void main(String[] args) {
        List<OOMObject> list = new ArrayList<>();
        while(true){
            list.add(new OOMObject());
        }
    }
}

运行结果

java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid11496.hprof ...
Heap dump file created [28278423 bytes in 0.076 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOf(Arrays.java:3210)
	at java.util.Arrays.copyOf(Arrays.java:3181)
	at java.util.ArrayList.grow(ArrayList.java:265)
	at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:239)
	at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:231)
	at java.util.ArrayList.add(ArrayList.java:462)
	at com.itsenfeng.staticDemo.Demo06.main(Demo06.java:13)

Process finished with exit code 1

上面我们通过设置java堆的大小限制为20M,然后不断往堆中创建对象,直到java堆内存溢出(OutOfMemoryError)。

Exception

Exception是程序本身可以处理的异常,可以通过catch捕捉。这种异常分两大类运行时异常非运行时异常(不受检查异常和检查异常)。 程序中应当尽可能去处理这些异常。

运行时异常都是RuntimeException类及其子类异常,常见的异常有:空指针异常(NullPointerException)、下标越界异常(IndexOutOfBoundsException)、算术异常(ArithmaticException)、类型转换异常(ClassCastException) 等,这些异常一般是由程序逻辑错误引起的, 程序应该从逻辑角度尽可能避免这类异常的发生。

非运行时异常是RuntimeException以外的异常类型上都属于Exception类及其子类。 从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过,如IO异常(IOException)、SQL(SQLException)等以及用户自定义的Exception异常。面对这种异常,一般我们选择抛出或者将有这些异常的代码放在try.....catch中处理。

下面举个例子带大家直观体会一下这两种异常:

import java.io.FileNotFoundException;

public class Demo07 {
    public static void main(String[] args){
        int array[] = {1,9,9,0,7,6};
        ddd a = new ddd();
        System.out.println(a.arrayout(array, 2));
        try {
            //此方法抛出的异常属于检查异常,必须处理
            a.findFile("f://t.txt");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        //运行结果
        //9
        //f://t.txt

    }

}
class ddd{
    public void findFile(String s) throws FileNotFoundException{
        if(s == null){
            /*下面的throw语句抛出的是检查异常,必须进行处理,否则编译不通过
            所以在方法的声明中,可以捕捉此异常,也可以throws此异常或异常父类,
            throws的话主函数调用该方法时,就要对该抛出的异常进行处理。
            */
            throw new FileNotFoundException();
        }else{
            System.out.println(s);
        }
    }
    public int arrayout(int a[],int index){
        if(index > a.length){
            /*ArrayIndexOutOfBoundsException异常属于非受检查异常,可以不处理
            下面的语句抛出这个异常,我们不必在方法的声明中throws此异常
            主函数调用此方法也可以不处理
            */
            throw new ArrayIndexOutOfBoundsException();
        }
        return a[index];
    }
}

throw和throws的说明:

1、throws出现在方法的声明中,表示该方法可能会抛出的异常,允许throws后面跟着多个异常类型

2、throw出现在方法体中,用于抛出异常,当方法在执行过程中遇到异常情况时,将异常信息封装为异常对象,然后throw,throw出异常后,也就直接跳出该方法了。throw不写在try....catch里面方法后要加throws

异常处理方式

介绍完这些异常后,我们再来介绍一下该如何去解决他们。

第一、在方法中用try...catch 语句捕获并处理异常,catach 语句可以有多个,用来匹配多个异常。

 try {

       //可能产生的异常的代码

   }catch (异常类型 异常变量) {

       //捕获并处理try抛出的异常
       //异常类型可以是其以及其父类

   }catch (异常类型 异常变量){

       //捕获并处理try抛出的异常
       //异常类型可以是其以及其父类

   }finally{

       //无论是出现异常,finally块中的代码都将被执行
     //finally可不写
   }

try 块: 用于捕获异常。其后可接零个或多个 catch 块,如果没有 catch 块,则必须跟⼀个 finally 块。
catch 块: 用于处理 try 捕获到的异常。
finally 块: 无论是否捕获或处理异常, finally 块里的语句都会被执行。当在 try 块或catch 块中遇到 return 语句时, finally 语句块将在方法返回之前被执行。

注意:当 try 语句和 finally 语句中都有 return 语句时,在⽅法返回之前,finally 语句的内容将被执⾏,并且 finally 语句的返回值将会覆盖原始的返回值。

public static int f(int value) {
 try {
      return value * value;
 } finally {
       if (value == 2) {
            return 0;
 }
 }
 }
 //结果返回0

在以下 3 种特殊情况下, finally 块不会被执行:
1.在 try 或 finally 块中用了 System.exit(int) 退出程序。但是,如果System.exit(int)在异常语句之后, finally 还是会被执行
2. 程序所在的线程死亡。
3. 关闭 CPU。

第二、对于处理不了的异常,在方法的声明处通过throws 语句抛出异常

 public void highLevelAccess() throws HighLevelException{

      try {
          ................
      }catch (Exception e) {
          ................
      }

   }

那么这两种方法有什么不同呢????

抛出异常:我们将这种称为渣男(具体方法)行为,遇到问题就把就把女孩子(异常)抛给前任(方法调用者),自己不负责,然后可能前任(方法调用者)也是渣男,又将女孩子(异常)抛给前前任(方法调用者的调用者),如果一直没有对其进行处理,那么最终抛到第一任(main方法)方法,第一任也没办法,第一任(main方法)再抛给jvm虚拟机,jvm虚拟机直接认定其没救了,终止她的生命。

捕获异常:这种行为是负责任的,我们直接将人家(异常)捕获,然后再catch解决掉。 对于捕获异常,当在try中发现异常语句后,异常语句后面的代码将不再执行,这里指的是try里面的代码。 一个try后面可以跟多个catch,但只会执行先匹配到的catch块。


自定义异常

在实际了开发中,jdk所拥有的异常种类是不够我们使用的,为此,我们有时需要自己自定义异常类:

步骤:

1、声明一个自定义异常类
2、将自定义类继承Exception(必须处理)或者RuntimeException(可以不处理)
3、编写两个构造器,一个空的,一个有参数的构造器(根据需要传输错误信息)

下面时自定义异常类的一个实例:

class FuShuException extends Exception
{
    private int value;

    FuShuException()
    {
        super();
    }
    FuShuException(String msg,int value)
    {
        super(msg);
        this.value = value;
    }

    public int getValue()
    {
        return value;
    }

}



class Demo
{
    int div(int a,int b)throws FuShuException
    {
        if(b<0) {
            //手动通过throw关键字抛出一个自定义异常对象。
            throw new FuShuException("出现了除数是负数的情况------ / by fushu", b);
        }
        return a/b;
    }
}


public class  Demo08
{
    public static void main(String[] args)
    {
        Demo d = new Demo();
        try
        {
            int x = d.div(4,-9);
            System.out.println("x="+x);
        }
        catch (FuShuException e)
        {
            System.out.println(e.toString());//输出异常发生时的详细信息
            System.out.println("错误的负数是:"+e.getValue());
        }
        System.out.println("over");
        /*运行结果
          com.itsenfeng.staticDemo.FuShuException: 出现了除数是负数的情况------ / by fushu
          错误的负数是:-9
          over
        */

    }
}

Throwable 类常用方法:

public string getMessage():返回异常发生时的简要描述
public string toString():返回异常发生时的详细信息
public string getLocalizedMessage():返回异常对象的本地化信息。使用Throwable 的⼦类覆盖这个方法,可以生成本地化信息。如果⼦类没有覆盖该方法,则该方法返回的信息与getMessage() 返回的结果相同
public void printStackTrace():在控制台上打印 Throwable 对象封装的异常信息

结语:

希望本篇博客对大家有帮助,如有不足与错误,欢迎大家指正!!!