Java-异常处理

一、异常的分类

在这里插入图片描述

Java编译器会对检查异常进行检查,而对运行时异常不会检查。也就是说对于编译时异常要么通过throws进行声明抛出,要么通过try…catch进行捕获处理,否则编译不通过。而运行时异常没有throws和try…catch依然可以编译通过。但是同样可以对其进行throws或try…catch。(可以把编译异常理解为炸弹,要么拆掉,要么抛出别人,否则炸死了程序)

1. 错误

如果应用程序出现了 Error,那么将无法恢复,只能重新启动应用程序,最典型的Error 的异常是:OutOfMemoryError(内存溢出)

2. 编译时异常(检查异常)

出现了这种异常必须显示的处理不显示处理 java 程序将无法编译通过

3. 运行时异常(RuntimeException类及其子类都被称为运行时异常。)

此种异常可以不用显示的处理,例如被 0 除异常,java 没有要求我们一定要处理


二、异常的捕获和处理掉需要采用 try 和 catch

try {
            
}catch (OneException e){
            
}catch (TwoException e){
            
}finally {

}
  • try 中包含了可能产生异常的代码
  • try 后面是 catch,catch 可以有一个或多个,catch 中是需要捕获的异常
  • 当 try 中的代码出现异常时,出现异常下面的代码不会执行,马上会跳转到相应的catch 语句块中,如果没有异常不会跳转到 catch 中
  • 如果try中有return,则执行完return后的子句(还是同一行语句return i++,执行了i++后不会返回,如果从这里返回则是返回i的中间缓存值,这要研究JVM),在返回前先执行finally中的语句,如果finally中也有return语句,则返回的入口不再是try中的return,而是直接从finally中的return返回
  • finally 表示,不管是出现异常,还是没有出现异常,finally 里的代码都执行,finally 和 catch可以分开使用,但 finally 必须和 try 一块使用

三、getMessage 和 printStackTrace()

  • 取得异常描述信息:getMessage()
  • 取得异常的堆栈信息(比较适合于程序调试阶段):printStackTrace();
public class Test {
    public static void main(String[] args) {
        int i1 = 100;
        int i2 = 0;
        try {
            int i3 = i1 / i2;
            System.out.println(i3);
        } catch (ArithmeticException e) {
            // e 是一个引用,它指向了堆中的 ArithmeticException
            // 通过 getMessage 可以得到异常的描述信息
            System.out.println(e.getMessage());
        }
    }
}

四、声明异常(抛出异常)

在方法定义处采用 throws 声明异常,如果声明的异常为编译异常,那么调用方法必须处理此异常

private static void readFile()
            throws FileNotFoundException, IOException { //声明异常,声明后调用者必须处理
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("test.txt");
        } finally {
            fis.close();
        }
}

捕获和处理

import java.io.*;

public class ExceptionTest {
    public static void main(String[] args) {
        // throws FileNotFoundException, IOException { //可以在此声明异常,这样就交给 java 虚拟机处理了,不建议这样使用
        // throws Exception { //可以采用此种方式声明异常,因为 Exception 是两个异常的父类
        try {
            readFile();
        }catch (FileNotFoundException e){ //不捕获异常就抛出(方法处声明)
            System.out.println(e.getMessage());
        }catch (IOException e){
            System.out.println(e.getMessage());
        }
    }
}

将 IOException 放到前面,会出现编译问题,因为 IOException 是 FileNotFoundException 的父类,所以截获了 IOException 异常后,IOException 的子异常都不会执行到,所以再次截获 FileNotFoundException 没有任何意义异常的截获一般按照由小到大的顺序,也就是先截获子异常,再截获父异常。(为了更精确提示)


五、手动抛出异常

public class ExceptionTest {
    public static void main(String[] args) {
        try {
            int ret = method1(1000, 0);
            System.out.println(ret);
        } catch (Exception iae) {
            System.out.println(iae.getMessage());
        }
    }

    private static int method1(int value1, int value2) {
        try {
            if (value2 == 0) { 手动抛出异常
                throw new IllegalArgumentException("除数为 0");
                //加入如下语句编译出错,throw相当于 return 语句
            }
            if (!(value1 > 0 && value1 <= 100)) {
                //手动抛出异常
                throw new IllegalArgumentException("被除数必须为 1~100 之间 的数据");
            }
            int value3 = value1 / value2;
            return value3;
        } finally {
            //throw 虽然类似 return 语句,但 finally 会执行的
            System.out.println("-----------finally------------");
        }
    }
}

运行结果:

-----------finally------------
除数为 0

异常处理,完全依赖于程序的返回
另外异常处理和程序逻辑混在一起,不好管理
异常是非常,程序语句应该具有一套完成的异常处理体系


六、方法覆盖与异常

方法覆盖的条件:子类方法不能抛出比父类方法更多的异常,但可以抛出父类方法异常的子异常


七、自定义异常

自定义异常通常继承于 Exception 或 RuntimeException,到底继承哪个应该看具体情况来定

//自定义的非受控异常类
public class MyException extends RuntimeException{
    public MyException() {
        //调用父类的默认构造函数
        super();
    }

    public MyException(String message) {
        //手动调用父类的构造方法
        super(message);
    }
}
public class Test {

    public static void main(String[] args) {
        try {
            method1(10, 0);
        } catch (MyException e) {
            //必须拦截,拦截后必须给出处理,如果不给出处理,就属于吃掉了该异常
            //系统将不给出任何提示,使程序的调试非常困难
            System.out.println(e.getMessage());
        }
    }


    private static void method1(int value1, int value2)
            throws MyException { //如果是受控异常必须声明(抛出)
        if (value2 == 0) {
            throw new MyException("除数为 0");
        }
        int value3 = value1 / value2;
        System.out.println(value3);
    }

}

在项目中往往官方没有具体的异常类去定义项目中的错误,所以要自定义异常类


八、结论(在软件开发中怎么解决异常让编译通过)

原则:到界面层(controller层)进行try…catch进行信息错误的提示(返回错误信息给前端,不必再一次抛出),其实在业务层或者数据库层也会try…catch,进行事务的回滚和业务需求,但同时会再一次抛出,由调用层判断处理和抛出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值