java异常

java异常

概述:程序在运行过程中出现的不正常现象或配置中产生的问题,不经过处理的异常将终止程序运行(开发过程中出现的语法错误和逻辑错误不是异常,语法错了,编译不通过,不会产生字节码文件,根本不能运行)。

在Java等面向对象的编程语言中,异常本身是一个类,产生异常就是创建异常对象并抛出了一个异常对象。目的是帮助我们找到程序中的问题,Java处理异常的方式是中断处理。

异常处理

java编程语言使用异常处理机制为程序提供异常处理能力

Throwable

所有错误和异常的父类

异常的体系结构

在这里插入图片描述

在这里插入图片描述

  1. Error:JVM、硬件、执行逻辑错误,不能手动处理

    如:StackOverflowError----------栈溢出错误

  2. Exception:程序在运行和配置中产生的问题

    • RuntimeException:运行时异常,可处理可不处理
    • CheckedException:检查(编译)时异常,编译异常,必须处理

注意:Exception除了RuntimeException及其子类外的所有子类都是检查时异常

类型说明
NullPointerException空指针异常
ArrayIndexOutBoundsException数组越界异常
ClassCastException类型转换异常
NumberFormatException数字格式化异常
ArithmeticException算术异常

Throwable成员方法

常用方法名描述
public String getMessage()返回此 throwable 的详细消息字符串
public String toString()返回此可抛出的简短描述
public void printStackTrace()把异常的错误信息输出在控制台
public class ExceptionDemo02 {
	public static void main(String[] args) {
        System.out.println("开始");
        method();
        System.out.println("结束");
	}
	public static void method() {
        try {
            int[] arr = {1, 2, 3};
            System.out.println(arr[3]); //new ArrayIndexOutOfBoundsException();
            System.out.println("这里能够访问到吗");
        } catch (ArrayIndexOutOfBoundsException e) { //new ArrayIndexOutOfBoundsException();
            // e.printStackTrace();
            //public String getMessage():返回此 throwable 的详细消息字符串
            // System.out.println(e.getMessage());
            //Index 3 out of bounds for length 3
            //public String toString():返回此可抛出的简短描述
            // System.out.println(e.toString());
            //java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
            //public void printStackTrace():把异常的错误信息输出在控制台
            e.printStackTrace();
            // java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
            // at com.itheima_02.ExceptionDemo02.method(ExceptionDemo02.java:18)
            // at com.itheima_02.ExceptionDemo02.main(ExceptionDemo02.java:11)
    	}
	}
}

程序执行产生异常的过程

在这里插入图片描述

异常产生的原因

  • 当程序在运行时遇到不符合规范的代码或结果时,会产生异常,可使用throws关键字手动抛出异常
  • 注意:throws关键字并没有真正处理异常,只是将异常抛给了调用者,即谁调用可能存在异常的成员,谁就处理该异常,若一直上抛直至main方法后,main方法仍不处理,则最终会由JVM进行处理,当我们对一个可能存在运行异常的代码不做任何处理时,系统会隐式默认使用throws关键字将异常抛给Exception,最终由JVM做默认处理,处理方式有如下两个步骤:
    • 把异常的名称,错误原因及异常出现的位置等信息输出在了控制台
    • 程序停止执行,所以最后才会输出异常信息并中断程序
  • 但是,如果是编译时异常,则没有默认处理方式,因为编译时异常时一定要显式处理的,所以没必要拥有默认处理方式

异常的传递

按照方法的调用链反向传递,如果始终没有处理异常,最终会有JVM进行默认的异常处理(打印堆栈跟踪信息)

public class TestException {
    /**
     * 异常的传递:按照方法的调用链反向传递,如果始终没有处理异常,最终会有JVM
     * 进行默认的异常处理(打印堆栈跟踪信息),例子:
     * main方法调用operation方法,operation方法调用show方法,当show方法出现异
     * 常而没有进行处理时,jvm会把未处理的异常反向抛给operation方法,operation
     * 方法也没有处理时,抛给mian方法,main方法还没有处理异常,jvm会进行默认的异常处
     * 理:打印堆栈跟踪信息
     * Exception in thread "main" java.lang.ArithmeticException: / by zero
     *     at com.company.TestException.show(TestException.java:24)
     *     at com.company.TestException.operation(TestException.java:15)
     *     at com.company.TestException.main(TestException.java:11)
     * @param args
     */
    public static void main(String[] args) {
        operation();
    }

    static void operation() {
        show();
    }

   static void show() {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个数字:");
        int i = sc.nextInt();
        System.out.println("请再输入一个数字:");
        int j = sc.nextInt();
        int a = i / j;
        System.out.println(a);
    }
}

Java的异常处理关键字

  • try:执行可能产生异常的代码,在发生异常的语句处直接跳到catch语句块,try语句块中异常语句后面的代码不再执行,如果没有异常,则不会跳转到catch语句块
  • catch:捕获并处理异常
  • finally:无论有无异常都执行此代码,除非退出JVM,它可以释放资源,根据需要可写可不写
  • throws:手动向上抛出异常,异常并未处理,谁调用谁处理
  • throw:声明方法一定有异常抛出,通常搭配try…catch或throws关键字使用,运行时异常可以不处理,检查时异常必须处理
try…catch方式处理异常
/**
 * Java的异常处理关键字:
 * try:执行可能产生异常的代码
 * catch:捕获并处理异常
 * finally:无论有无异常都执行此代码,用来释放资源,除非退出java虚拟机
 * throws:手动抛出异常
 * throw:声明方法可能要抛出的异常
 */
public class TestException {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入被除数:");
        int i = sc.nextInt();
        System.out.println("请输入除数:");
        int  j = sc.nextInt();
        int consult;//商
        /**
         * try{
         * 执行可能产生异常的代码
         * }catch(异常类型 引用名){
         *     异常处理语句
         * }finally{
         *     必定执行的代码,用来释放资源,除非退出java虚拟机,只有在try或者catch中调用退出JVM的相关方法(比如System.exit(0)),此时finally才不会执行,否则finally永远会执行。
         * }
         */
        try{
            consult = i / j;//除数不能为0,若为0,报算术异常:ArithmeticException
            // 当发生异常时,在异常语句处直接跳到catch语句块中,try语句块中后面的语句不执行
	  System.out.println(i + " / " + j + " = " + consult);//不执行
        }catch(Exception e){//这里可以写异常的父类,也可以写具体的子类,但是一定要
                            // 保证是该类型的异常,不然会出现异常不匹配
            e.printStackTrace();//输出异常的堆栈信息
        }finally {
            System.out.println("总是有我!");
        }
    }
}

在这里插入图片描述

  • 执行流程
    • 程序从 try 里面的代码开始执行
    • 出现异常,就会跳转到对应的 catch 里面去执行
    • 执行完毕之后,程序还可以继续往下执行
多重catch
public class TestException {
    public static void main(String[] args) {
        /**
         * try{
         * 执行可能产生异常的代码
         * }catch(异常类型 引用名){
         *     异常处理语句
         * }catch(异常类型 引用名){
         *     异常处理语句
         * }catch(异常类型 引用名){
         *     异常处理语句
         * }finally{
         *     必定执行的代码
         * }
         * (1)发生异常时,从前往后按顺序逐个匹配
         * (2)只执行第一个匹配的异常处理语句
         * (3)子类异常在前,父类异常在后
         * 注意:在多重catch的异常处理中,父类的异常处理语句必须放在所有
         * 异常处理语句的后面,否则将会报异常已被捕获错误
         */
        try {
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入被除数:");
            int i = sc.nextInt();
            System.out.println("请输入除数:");
            int j = sc.nextInt();
            int consult;//商
            consult = i / j;
            System.out.println(i + " / " + j + " = " + consult);
        } catch (InputMismatchException e) {
            System.out.println("输入类型不匹配异常,只能输入数字!!!");
        } catch (ArithmeticException e) {
            System.out.println("算术异常,除数不能为0!!!");
        } catch (Exception e) {
            System.out.println("我是所有异常的父类!");
        } finally {
            System.out.println("我可以释放资源!");
        }
    }
}
在这里插入图片描述在这里插入图片描述在这里插入图片描述

在这里插入图片描述

throws:向上抛出异常

概述:定义功能方法时,需要把出现的异常暴露出来让调用者去处理,就通过throws在方法上声明。

throws后面可以跟多个异常类名,用逗号隔开。尽量不要在main方法上抛出异常

public class TestException {
    /**
     * 对于被调用者上抛的异常,可以使用try{}catch(){}语句进行异常处理,也
     * 可以使用throws关键字继续把异常往上抛,如果最终没有对异常进行处理,
     * 会默认交给JVM处理,JVM会打印异常的堆栈信息,程序将被打断
     */
    public static void main(String[] args) throws Exception {
            show();
        /**
         * try{
         *     show();
         * }catch(Exception e){
         *     e.printStackTrace();
         * }
         */
    }

    static void show()  throws Exception{
        /**
         *此段代码可能存在异常,但是这里先不处理,使用throws关键字抛出异常,
         * 将异常抛给上一级,就是把异常抛给它的调用者,这里是main方法
         */
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入被除数:");
        int i = sc.nextInt();
        System.out.println("请输入除数:");
        int j = sc.nextInt();
        int consult;//商
        consult = i / j;
        System.out.println(i + " / " + j + " = " + consult);
    }
}
throw:手动抛出异常

概述:在功能方法内部出现的某种情况,程序不能继续运行,需要进行跳转时,就用throw把异常对象抛出。

手动抛出异常,通常搭配try…catch或throws关键字使用,运行时异常可以不处理,检查时异常必须处理

public class TestException {
    public static void main(String[] args) throws Exception {
        show();
    }
    static void show() throws Exception {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入被除数:");
        int i = sc.nextInt();
        System.out.println("请输入除数:");
        int j = sc.nextInt();
        int consult;//商
        consult = i / j;
        System.out.println(i + " / " + j + " = " + consult);
        /**
         * throw new 异常类型(提示):手动抛出一个异常,告诉别人这里有个异常,这个
         * 异常如果是运行时异常可以不处理,如果是检查时异常必须处理,否则编译不能通
         * 过,可以使用throws关键字往上抛,也可以用try{}catch(){}语句进行处理
         */
        throw new Exception("这里会出现算术异常");
    }
}
  • 带有异常声明的方法覆盖:
    • 方法名、参数列表、返回值类型必须与父类相同
    • 子类的访问修饰符范围大于等于父类
    • 子类中的方法,不能抛出比父类更多、范围更广的检查时异常

异常注意事项

  • 多个异常使用捕获又该如何处理呢?

    1. 多个异常分别处理。
    2. 多个异常一次捕获,多次处理。
    3. 多个异常一次捕获一次处理。

一般我们是使用一次捕获多次处理方式,格式如下:

try{
   //编写可能会出现异常的代码
}catch(异常类型A e){  //当try中出现A类型异常,就用该catch来捕获.
   //处理异常的代码
  	//记录日志/打印异常信息/继续抛出异常
}catch(异常类型B e){ //当try中出现B类型异常,就用该catch来捕获.
  	//处理异常的代码
  	//记录日志/打印异常信息/继续抛出异常
}
  • 注意:这种异常处理方式,要求多个catch中的异常不能相同,并且若catch中的多个异常之间有继承关系,那么子类异常必须写在父类异常前面,平级关系的异常没有先后顺序的要求。
  • 注意:
    try里面的代码越少越好。
    catch里面必须有内容,至少要给出一个简单的提示信息。
  • 一旦try里面出现了异常,JVM就会实例化这个异常,并将这个异常对象抛出,如果和catch语句里的异常类相匹配,就会执行相应的catch里面的处理,然后结束try…catch语句,继续执行后面的代码。
  • 可以明确的异常尽量明确,不要用父类来处理,以便提高运行的效率。
  • 运行时异常被抛出可以不处理。即不捕获也不声明抛出。
  • 如果finally有return语句,永远返回finally中的结果,应避免在finally中写return的情况.
  • 如果父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者是父类异常的子类或者不抛出异常。
  • 父类方法没有抛出异常,子类重写父类该方法时也不可抛出异常。此时子类产生该异常,只能捕获处理,不能声明抛出

throws与throw的区别

throwsthrow
用在方法声明后面,跟的是异常类型用在方法体重,跟的是异常对象
表示抛出异常,由该方法的调用者来处理表示抛出异常,由方法体内的语句处理
表示出现异常的一种可能,并不一定会发生这些异常执行throw一定抛出了某种异常

final,finally和finalize的区别:

1)final:表示最终的,可以修饰类、成员变量和成员方法

修饰类,类不能被继承

修饰成员变量,变量是常量

修饰成员方法,方法不能被重写

2)finally:是异常处理的一部分,用来释放资源

一般来说,finally后面的代码一定会执行

特殊情况:在执行到finally之前JVM退出了

3)finalize:Object类里面的一个方法,用于垃圾回收

注意:

如果catch里面有return语句,fianlly里面的代码会在return语句之前执行。确切地说,应该在中间执行。
程序执行到return语句时会形成返回路径,如果后面还有finally语句,就继续执行finally里面的代码,再次回到以前的返回路径,返回以前的返回值

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值