八、异常的学习

8.1异常的继承体系

在Java中,使用类 Throwable 来描述所有的不正常的情况。 Throwable有两个子类,Error 和 Exception 。其中 Error 用来描述发生在JVM级别的错误信息,这些错误,无法被处理。 Exception 用来描述程序在编译或者运行的过程中遇到的异常信息,这些异常一旦处理了,对程序的编译和运行是没有影响的。

Throwable:Error\Exception

Error:VirtualMachineError(虚拟机错误)、OutOfMemoryError(内存溢出)、ThreadDeath(线程死锁)

Exception:RuntimeException、IOException(IO异常)、SQLException(SQL异常)

RuntimeException:NullPointerException(空指针异常)、ArrayIndexOutOfBoundsException(数组下标越界异常)、ArithmeticException(算数异常)、ClassCastException(类型转换异常)

异常可以分为 运行时异常编译时异常

8.2异常处理的语法

try { // 将可能会出现异常的代码放到这里执行 // 一旦try中的代码出现了异常,则从出现异常的位置开始,到try的大括号的扩回,这一段代码就不执行了。 }catch (需要捕获的异常的类型 标识符) { // 如果try中的代码出现了异常,并且异常对象的类型和捕获的类型一致 // 这里的代码将会执行 // 一旦一个异常被捕获了,那么这个异常将不再影响程序的编译和执行 }

  1. 将可能出异常的代码片段放入try的语句块中,

  2. jvm在运行程序时,如果出现了异常,则从出现异常的位置开始,到try的大括号的扩回,这一段代码就不执行了。

  3. jvm在运行程序时,如果出现了异常,会自动创建一个具体的异常对象

  4. catch(需要捕获的异常的类型 标识符){}用于捕获异常操作

  5. jvm创建的异常对象如果与catch捕获的异常对象类型匹配(或者向上造型没问题),就会就将地址值赋值给异常类型变量。

  6. catch捕获到异常对象后,就会执行对应的{}里的代码。这个异常将不再影响程序的编译和执行

  7. catch模块如何处理异常呢? 比如打印异常信息,供程序员查看,然后进行调试,或者继续抛给调用者

案例:

      try{
            int[]  nums = {1,2,3,4,5};
            for (int i = 0; i <= nums.length; i++) {
                int num = nums[i];
                System.out.println("num = " + num);
            }
        }catch (Exception e){
            //System.out.println("发生了异常");
            e.printStackTrace();
        }
        System.out.println("main方法结束");
    }
}
8.3多种异常的处理

如果多个catch的异常之间不存在继承关系,不需要考虑书写顺序。 如果多个catch的异常之间存在继承关系,则必须子类异常在前,父类异常在后。

案例:

 try{
            int[] nums = new int[5];
            nums[5] = 100;
            String str = null;
            int length = str.length();
        }catch(ArrayIndexOutOfBoundsException e){
            System.out.println("--数组下标越界--");
        }catch (NullPointerException e){
            System.out.println("--空指针异常--");
        }catch (Exception e){
            System.out.println("--异常--");
        }
        //简化版本1:没有继承关系的异常类型,可以写在一个catch中,使用|分开
        // 前提条件:处理逻辑一样
        try{
            int[] nums = new int[5];
            nums[5] = 100;
            String str = null;
            int length = str.length();
        }catch (ArrayIndexOutOfBoundsException|NullPointerException e){
            e.printStackTrace();
        }
        //简化版本2: 使用这些异常的共同父类型即可   前提条件:处理逻辑一样
        try{
            int[] nums = new int[5];
            nums[5] = 100;
            String str = null;
            int length = str.length();
        }catch (Exception e){
            e.printStackTrace();
        }

8.4 finally模块

finally用在try后面,或者catch后面,作为异常捕获的结尾。

特点:finally中的语句始终会执行。(无论try中的代码是否出现了异常,这里的代码都会执行)

使用场景:会在finally中做资源释放、流的关闭等操作。

String[] names = null;
try{
    names = new String[3];
    String name = names[1];
    int length = name.length();
}catch (Exception e){
    e.printStackTrace();
}finally {
    names[1] = "zhangsan";
}
System.out.println(Arrays.toString(names));
System.out.println("--main方法结束--");
​
// finally的应用场景: 一般用于流的关闭操作。
InputStream is = null;
try{
    is = Exception03.class.getClassLoader().getResourceAsStream("");
    BufferedImage image = ImageIO.read(is);
}catch (Exception e){
    e.printStackTrace();
}finally {
    try {
        is.close();
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}
结果
java.lang.NullPointerException
    at com.se.day01.aException.Exception03.main(Exception03.java:21)
[null, zhangsan, null]
--main方法结束--
​
Process finished with exit code 0
​
8.5研究一下finally和return的特点
  1. 当try里有return关键字,以及finally模块没有return 先执行finally模块代码,然后再执行try里的return关键字

  2. try和finally里都有return, 一定执行的finally里的return.

案例:

  public static void main(String[] args){
        int result = test4();
        System.out.println(result);
    }
    public static int test4(){
        //finally 语句块中有 return 语句
        int i = 1;
        try {
            i++;
            System.out.println("try block, i = " + i);
            return i;
        } catch (Exception e) {
            i++;
            System.out.println("catch block i = " + i);
            return i;
        } finally {
            i++;
            System.out.println("finally block i = " + i);
            return i;
        }
    }
    public static int test3(){
        //try 语句块中有 return 语句时的整体执行顺序
        int i = 1;
        try{
            i++;
            System.out.println("try block, i = " + i);
            return i;
        } catch (Exception e) {
            i ++;
            System.out.println("catch block i = " + i);
            return i;
        } finally {
            i = 10;
            System.out.println("finally block i = " + i);
        }
    }
    public static int test2(){
        int i = 1;
        try {
            i++;
            throw new Exception();
        } catch (Exception e) {
            i--;
            System.out.println("catch block i = " + i);
        } finally {
            i = 10;
            System.out.println("finally block i = " + i);
        }
        return i;
    }
    public static int test1(){
        int i = 1;
        try {
            i++;
            System.out.println("try block, i = "+i);
        } catch (Exception e) {
            i--;
            System.out.println("catch block i = "+i);
        } finally {
            i = 10;
            System.out.println("finally block i = "+i);
        }
        return i;
    }
​
try block, i = 2
finally block i = 3
3
8.6如何自定义异常类型:
  1. 继承Exception 或者继承RuntimeException ,定义两个构造器即可。模拟已经存在的子类异常

  2. 继承Exception的自定义异常,是编译时异常

  3. 继承RuntimeException的自定义异常,是运行时异常 throw和throws的特点:

  4. throw是用在方法里,用于将一个异常对象抛出,自己不处理,抛给调用者,谁调用这个方法,谁就是调用者。

  5. throws是用在方法的定义上。表示告诉调用者需要处理的异常类型。

  6. throw的如果是编译时异常,必须throws(必须告诉调用者) 4.throw的如果是runtimeException, 就没有必要throws了。

案例:

 public static void main(String[] args) {
        try {
            Person p =  new Person("小明",130);
        }catch (AgeIllegalException e){
            e.printStackTrace();
        }
    }
}
class Person{
    private String name;
    private int age;
    public Person(String name, int age) throws AgeIllegalException{
        this.name = name;
        if (age<1 || age>120){
            throw new AgeIllegalException("年龄不合理,不应该<1或者大于120");
        }
        this.age = age;
    }
}
​
class AgeIllegalException extends Exception {
    public AgeIllegalException() {
        super();
    }
    public AgeIllegalException(String message) {
        super(message);
    }
}
com.se.day01.aException.AgeIllegalException: 年龄不合理,不应该<1或者大于120
    at com.se.day01.aException.Person.<init>(Exception05.java:30)
    at com.se.day01.aException.Exception05.main(Exception05.java:18)
8.7面试题 : 简述 final、finally、finalize 的区别。

性质不同:(1)final为关键字;(2)finalize()为方法;(3)finally为为区块标志,用于try语句中;

作用不同:(1)final为用于标识常量的关键字,final标识的关键字存储在常量池中((2)finalize()方法在Object中进行了定义,用于在对象“消失”时,由JVM进行调用用于对对象 进行垃圾回收,类似于C++中的析构函数;用户自定义时,用于释放对象占用的资源(比如进行 I/0操作); (3)finally{}用于标识代码块,与try{ }进行配合,不论try中的代码执行完或没有执行完(这里指有异常),该代码块之中的程序必定会进行 案例

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值