阶段一/常用工具/异常

目录

异常的简介

异常处理

try-catch-finally

throw & throws

自定义异常

异常链


 

异常的简介

什么是异常

  • 在程序运行过程中,意外发生的情况,背离我们程序本身的意图的表现,都可以理解为异常
  • 当成程序在运行期间出现了异常,若置之不理,程序可能会不正常运行、强制中断运行、造成用户数据丢失、资源无法正常释放、直接导致系统崩溃。

异常的分类

在Java中,通过Throwable及其子类描述各种不同类型的异常

  • Throwable
    • Error:程序无法处理的错误,表示应用程序中较严重的问题,大多数错误与代码编写着执行的操作无关,而表示代码运行时JVM(Java虚拟机)出现的问题,这些错误是不可查的,在应用程序的控制处理能力之外,对于设计合理的应用程序来说,即使确实发生了错误,本质上也不应该试图去处理他所引起的异常状况,故我们编写程序时无需关心这类异常。
      • Java虚拟机运行错误(Virtual MachineError)
      • 当JVM不再有继续执行操作所需的内存资源时,将出现OutOfMemoryError
    • Exception:程序本身可以处理的一场,异常处理通常指针对这种类型异常的处理
      • checked exception:编译器要求必须处理的异常,是RuntimeException及其子类以外,其他的Exception类的子类
        • IOException(IO异常)
        • SQLException(SQL异常)
      • unchecked execption:编译器不要求强制处理的异常,RuntimeException及其子类异常。
        • NullPointerException(空指针异常)
        • IndexOutOfBoundsException(下标越界异常)
        • ArithmeticException(算数异常)
        • ClassCastException(类型转换异常)

异常处理

通过5个关键字来实现:try、catch、finally、throw、throws

try-catch-finally

  • try:捕获异常
  • catch:处理try捕获到的异常
  • finally:无论是否发生异常代码总能执行,try-catch-finally之后的语句也是无论是否有异常都会执行,这边我们注意一下:当没有异常或者异常和catch语句能匹配上,finally语句快和try-catch-finally后续的语句均能执行,但是如果产生的异常和catch语句能匹配不上,则finally语句块依旧会执行,但是try-catch-finally后续的语句就不会执行了。尽量添加finally语句块去释放占用的资源。
  • try块后可接零个或多个catch块,若没有catch块,则必须跟一个finally块。
  • 多重catch语句捕获异常时,要注意范围,及大范围(父类)后置,因为当捕获到了一个异常时,剩下的catch语句就不再进行匹配。
  • try - catch - finally代码块中定义的都是局部变量,生效范围只在他们各自的{}之内。
  • 有时候尽管我们在catch语句块中处理了异常,但是我们不希望程序继续执行finally以及try-catch-finally后面的语句,这时候可以在相应的catch块里添加System.exit(数字),通常1-255之间,这时候程序就会终止
  • 关于retrun语句,return语句可以分别出现在try、catch以及finally块中,但是由于finally语句块一定要执行,所以当存在finally时,会先执行完finally中的代码再执行return。⚠️ 如果前面的try-catch代码块中有return返回值,finally代码块中也有return返回值的话,最后返回的时finally中return的值)   

这边穿插一个ArrayStoreException

  • 异常说明:数组中包含不兼容的值的异常
  • 出现条件:数组中实际传入的数据与预定不符,譬如子类数组经过向上转型后,传入父类对象。
class Father{

}
class Son extends Father{

}
public class Test {
    public static void main(String[] args){
        //定义长度为10 的子类数组
        Son[] sons = new Son[10];
        // 向上转型,设置父类数组引用指向数组
        Father[] fats = sons;
        // 数组中插入父类对象
        fats[0] = new Father();
    }
}

运行结果:

Exception in thread "main" java.lang.ArrayStoreException: mytest.Father
	at mytest.Test.main(Test.java:15)

return语句可以分别出现在try、catch以及finally块中,但是由于finally语句块一定要执行,所以当存在finally时,会先执行完finally中的代码再执行return。⚠️ 如果前面的try-catch代码块中有return返回值,finally代码块中也有return返回值的话,最后返回的时finally中return的值)。

举例如下,无论是否发生异常没,result的值都是finally带回的返回值1000。若把finally的return语句去掉,就符合我们的逻辑了。

public class TryClassTwo {
    public static void main(String[] args){
        int result = test();
        System.out.println("one 和 two 的商是:" + result);
    }
    public static int test(){
        Scanner input = new Scanner(System.in);
        System.out.println("======运算开始=======");
        try{
            System.out.print("请输入第一个整数: ");
            int one = input.nextInt();
            System.out.print("请输入第二个整数: ");
            int two = input.nextInt();
            return one / two;
        }catch (ArithmeticException e){
            System.out.println("除数不允许为0 ");
            return 0;
        }finally {
            System.out.println("======运算结束=======");
            return 1000;
        }
    }
}

输入12和4,输出

======运算开始=======
请输入第一个整数: 12
请输入第二个整数: 4
======运算结束=======
one 和 two 的商是:1000

输入12和0,输出

======运算开始=======
请输入第一个整数: 12
请输入第二个整数: 0
除数不允许为0 
======运算结束=======
one 和 two 的商是:1000

throw & throws

可以通过 throws 关键字声明方法要抛出何种类型的异常。通过throw将产生的异常抛出。

若一个方法可能会出现异常,但没有能力处理这种异常,可以在方法声明处用throws子句来声明抛出异常

public void demoMethod() throws Exception1, Exception2, ... ExceptionN {
    // 可能产生异常的代码
}
  • throws语句用在方法定义时声明该方法要抛出的异常类型
  • 当方法抛出异常列表中的异常时,方法将不对这些类型及其子类型的异常做处理,而抛向调用该方法的方法,由他去处理。
  • 通过throws抛出异常时,针对可能出现的多种情况,解决方案
    • throws后面接多个异常类型,中间用逗号分隔,非检查异常不会强制要求调用函数处理
    • throws后面接Exception,这时调用函数必须处理Exception,因为Exception还包含检查异常
  • 异常的作用
    • 规避可能出现的风险
    • 完成一些程序的逻辑
  • throw 抛出异常对象的处理方案
    • 通过try..catch包含throw语句--自己抛出自己处理
    • 通过throws在方法声明处抛出异常类型--谁调用谁处理,调用者可以自己处理,也可以继续上抛
      • 此时可以抛出与throw对象相同的类型或者其父类
    • 通过throw语句标识抛出对象的时候,不建议抛出非检查异常
  • 当子类重写父类异常的方法时,声明的必须是父类方法所声明异常的同类或子类。
public class HotelAgeException extends Exception{
    public HotelAgeException(){
        super("HotelAgeException,18以下,80以上的住客必须由亲友陪同");
    }
}

class SubException extends HotelAgeException{

}
public class FatherTest {
    public void test() throws HotelAgeException{
        throw new HotelAgeException();
    }
}

 

public class SubTest extends FatherTest {
//    @Override
//    public void test() throws Exception { //报错
//    }

//    @Override
//    public void test() throws RuntimeException { // 可以,是父类方法所声明异常的同类
//    }
    @Override
    public void test() throws SubException { // 也可以,是父类方法所声明异常的子类
    }
}

 

自定义异常

所谓的自定义异常就是定义一个类,去继承Throwable类或其子类。

自定义异常属于检查异常还是非检查异常?
这要看在定义自定义异常类时所继承的父类,如果父类属于检查异常,则自定义异常也就是检查异常,反之亦然。

自定义异常只能抛出后(throw)后才能卸载catch里吗?
是的,自定义机场需要先经过throw抛出,才能被catch捕获,是无法自动被程序捕获并处理的。 

异常链

将异常发生的原因一个一个的串起来,即把底层的异常信息传给上层,这样逐层抛出。可以将之前的异常作为参数传入新的异常对象的构造器;也可以调用新异常的initCause,将其作为参数传入。

public class TryDemo5 {
    public static void main(String[] args){
        try {
            testThree();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static void testOne() throws HotelAgeException {
        throw new HotelAgeException();
    }

    public static void testTwo() throws Exception {
        try {
            testOne();
        } catch (HotelAgeException e) {
            throw new Exception("我是新产生的异常1", e);
        }
    }
    public static void testThree() throws Exception {
        try {
            testTwo();
        } catch (Exception e) {
            Exception e1 = new Exception("我是新产生的异常2");
            e1.initCause(e);
            throw e1;
        }
    }
}

输出

java.lang.Exception: 我是新产生的异常2
	at com.imooc.exception.TryDemo5.testThree(TryDemo5.java:26)
	at com.imooc.exception.TryDemo5.main(TryDemo5.java:6)
Caused by: java.lang.Exception: 我是新产生的异常1
	at com.imooc.exception.TryDemo5.testTwo(TryDemo5.java:19)
	at com.imooc.exception.TryDemo5.testThree(TryDemo5.java:24)
	... 1 more
Caused by: com.imooc.exception.HotelAgeException: HotelAgeException,18以下,80以上的住客必须由亲友陪同
	at com.imooc.exception.TryDemo5.testOne(TryDemo5.java:12)
	at com.imooc.exception.TryDemo5.testTwo(TryDemo5.java:17)
	... 2 more

下面这种方式只会显示最后一层异常,而会丢失之前的异常信息

//这种方式容易丢掉异常
public static void testOne() throws HotelAgeException {
    throw new HotelAgeException();
}

public static void testTwo() throws Exception {
    try {
        testOne();
    } catch (HotelAgeException e) {
        throw new Exception("我是新产生的异常1");
    }
}
public static void testThree() throws Exception {
    try {
        testTwo();
    } catch (Exception e) {
        throw new Exception("我是新产生的异常2");
    }
}

输出:

java.lang.Exception: 我是新产生的异常2
	at com.imooc.exception.TryDemo5.testThree(TryDemo5.java:47)
	at com.imooc.exception.TryDemo5.main(TryDemo5.java:6)

 

参考:慕课网-Java工程师

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值