Java中的异常

Java基础

浏览数:84

2019-8-20

AD:资源代下载服务

异常

异常体系:

--------| Throwable (实现类描述java的错误和异常)所有异常或者错误类的超类
------------| Error (错误)错误一般是由于jvm或者是硬件引发的问题,一般不通过代码去处理。
------------| Exception(异常)需要通过代码去处理
----------------| RuntimeException (运行时异常)
----------------| 非运行时异常

一、Throwable

Throwable常用的方法:

toString()  返回当前异常对象的完整类名+异常信息。(输出该异常的类名)
getMessage() 返回的是创建Throwable传入的字符串信息。输出异常的信息,需要通过构造方法传入异常信息(例如病态信息)。
printStackTrace() 打印异常的栈信息。

Demo:

class Demo
{
    public static void main(String[] args) 
    {
        /*
        //创建了一个Throwable对象。
        Throwable t = new Throwable("感冒..");
        String info = t.toString();
        String message = t.getMessage();
        System.out.println("toString: "+ info);  // java.lang.Throwable  包名+类名 = 完整类名
        System.out.println("message: "+ message);
        */
        test();
    }

    public static void test(){
        //
        Throwable t = new Throwable();
        t.printStackTrace();
    }
}

Demo2:

class Demo2
{
    public static void main(String[] args) 
    {
        int[] arr = null;
        div(4,0,arr);
    }
    public static void div(int a , int b,int[] arr){
        int c = 0;
        try{
            c = a/b;  //jvm在这句话的时候发现了不正常的情况,那么就会创建一个对应的异常对象。
            System.out.println("数组的长度:"+ arr.length);
        }catch(ArithmeticException e){
            //处理异常的代码
            System.out.println("异常处理了");
            System.out.println("toString:"+ e.toString());
        }catch(NullPointerException e){
            System.out.println("出现了空指针异常");
        }catch(Exception e){  
            System.out.println("任何异常都能在此处捕获");
        }
        System.out.println("c="+c);
    }
}

下面的信息是通过printStackTrace方法打印出来的:

Exception in thread "main" java.lang.ArithmeticException: / by zero
        at Demo10.div(Demo10.java:10)
        at Demo10.main(Demo10.java:5)

信息是通过printStackTrace方法打印出来:

Exception in thread "main" java.lang.ArithmeticException: / by zero
    at Demo.div(Demo.java:10)
    at Demo.main(Demo.java:5)

异常对象的由来:

jvm运行到a/b这个语句的时候,发现b为0,除数为0在是属于不正常的情况,
jvm一旦发现了这种不正常的情况时候,那么jvm就会马上创建
一个对应的异常对象,并且会调用这个异常对象的printStackTrace的方法来处理。

二、Error

一般是由于jvm或者是硬件引发的问题,一般不通过代码去处理。

区分错误与异常:

如果程序出现了不正常的信息,如果不正常的信息的类名是以Error结尾的,那么肯定是一个错误。
如果是以Exception结尾的,那么肯定就是一个异常。

class Demo9 
{
    public static void main(String[] args) 
    {
        //java虚拟机在默认的情况下只能管理64m内存。
        byte[] buf = new byte[1024*1024];
        System.out.println("Hello World!");
    }
}

三、Exception

异常的处理方式

1.捕获处理

格式:

try{
    可能发生异常的代码;
}catch(捕获的异常类型 变量名){
    处理异常的代码;
}

注意的事项:

  1. 如果try块中代码出了异常经过了处理之后,那么try-catch块外面的代码可以正常执行。
  2. 如果try块中出了异常的代码,那么在try块中出现异常代码后面的代码是不会执行了。
  3. 一个try块后面是可以跟有多个catch块的,也就是一个try块可以捕获多种异常的类型。
  4. 一个try块可以捕获多种异常的类型,但是捕获的异常类型必须从小到大进行捕获,否则编译报错。

注意:捕获处理不能直接捕获Exception,因为在现实开发中遇到不同的异常类型的时候,往往会有不同的处理方式。所以要分开不同的异常类型处理。

2.抛出处理(throw throws)

注意的细节:

  1. 如果一个方法的内部抛出了一个异常对象,那么必须要在方法上声明抛出。
  2. 如果调用了一个声明抛出异常 的方法,那么调用者必须要处理异常。
  3. 如果一个方法内部抛出了一个异常对象,那么throw语句后面的代码都不会再执行了(一个方法遇到了throw关键字,该方法也会马上停止执行的)。
  4. 在一种情况下,只能抛出一种类型异常对象。

throw与throws两个关键字:

  1. throw关键字是用于方法内部的,throws是用于方法声声明上的。
  2. throw关键字是用于方法内部抛出一个异常对象的,throws关键字是用于在方法声明上声明抛出异常类型的。
  3. throw关键字后面只能有一个异常对象,throws后面一次可以声明抛出多种类型的异常。

何时使用抛出处理?何时捕获处理?原则是如何?
如果需要通知到调用者,代码出了问题,那么这时候就使用抛出处理.
如果代码是直接与用户打交道,遇到了异常,这时候就应该使用捕获处理。

class Demo 
{
    public static void main(String[] args) 
    {
        try{
            int[] arr = null;
            div(4,0,arr); //调用了一个 声明抛出异常类型的方法
        }catch(Exception e){
            System.out.println("出现异常了");
            e.printStackTrace();
        }
        
    }


    public static void div(int a, int b,int[] arr) throws Exception,NullPointerException {
        if(b==0){
            throw new Exception(); //抛出一个异常对象
        }else if(arr==null){
            throw new  NullPointerException();
        }
        int c = a/b;
        System.out.println("c="+c);
    }
}

四、自定义异常

根据实际需求,需要对某一些特定的情况的异常进行定义。

需求:吃饭付款,钱不够则抛出异常

NoEnoughMoneyException:

class NoEnoughMoneyException extends Exception {

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

}


class Demo 
{
    public static void main(String[] args) 
    {
        try{
            eat(9);

        }catch(NoEnoughMoneyException e){
            e.printStackTrace();
            System.out.println("押手机回家拿钱");
        }
    }


    public static void eat(int money) throws NoEnoughMoneyException{
        if(money<10){
            throw new NoEnoughMoneyException("吃霸王餐");
        }
        System.out.println("吃上了香喷喷的饭菜~");
    }
}

注意:

  • 子类不能抛出比父类的异常更大的异常。
  • 子类重写父类方法可以抛出和父类一样的异常,或者不抛出异常。
  • 子类覆盖父类方法是,父类方法抛出异常,子类的覆盖方法可以不抛出异常,或者抛出父类方法的异常,或者该父类方法异常的子类。
  • 父类方法抛出了多个异常,子类覆盖方法时,只能抛出父类异常的子集
  • 父类没有抛出异常子类不可抛出异常
  • 子类发生非运行时异常,需要进行try{}catch的(){}处理,不能抛出。
  • 子类不能比父类抛出更多的异常

五、运行时异常与编译时异常

异常体系:

--------| Throwable  所有错误或者异常的父类
--------------| Error(错误)
--------------| Exception(异常) 异常一般都通过代码处理 

------------------| 运行时异常: 如果一个方法内部抛出了一个运行时异常,那么方法上可以声明也可以不声明,调用者可以以处理也可以不处理。
------------------| 编译时异常(非运行时异常、受检异常):  如果一个方法内部抛出了一个编译时异常对象,那么方法上就必须要声明,而且调用者也必须要处理。

运行时异常: RuntimeException以及RuntimeException子类都是属于运行时异常。

编译时异常: 除了运行时异常就是编译异常。

为什么java编译器会如此严格要求编译时异常,对运行时异常如此宽松?
运行时异常都是可以通过程序员良好的编程习惯去避免,所以java编译器就没有严格要求处理运行时异常。

六、finally块

  • finally块的使用前提是必须要存在try块才能使用。
  • finally块的代码在任何情况下都会执行的,除了jvm退出的情况。
  • finally非常适合做资源释放的工作,这样子可以保证资源文件在任何情况下都会被释放。

try-catch的三种组合方式:

第一种: 比较适用于有异常要处理,但是没有资源要释放的。

try{
    可能发生异常的代码
}catch(捕获的异常类型 变量名){
    处理异常的代码
}

第二种:比较适用于既有异常要处理又要释放资源的代码。

try{
    可能发生异常的代码
}catch(捕获的异常类型 变量名){
    处理异常的代码
}finally{ 
    释放资源的代码;
}

第三种: 比较适用于内部抛出的是运行时异常,并且有资源要被释放。

try{
    可能发生异常的代码
}finally{ 
    释放资源的代码;
}

demo:

class Demo
{
    public static void main(String[] args) 
    {
        div(4,0);
    }

    public static void div(int a, int b){
        try{
            if(b==0){
                System.exit(0);//退出jvm
            }
            int c = a/b;
            System.out.println("c="+ c);

        }catch(Exception e){
            System.out.println("出了除数为0的异常...");
            throw e;
        }finally{
            System.out.println("finall块的代码执行了..");
        }
    }
}

作者:JS_HCX