freyhe

导航

05.异常处理

1.异常的体系结构

image-20220209210045537

异常的体系结构
java.lang.Throwable
1-----java.lang.Error:一般不编写针对性的代码进行处理。
1.1------一般有栈溢出和堆溢出

image-20220209213056253

​ 2-----java.lang.Exception:可以进行异常的处理
​ 2.1------编译时异常(checked,受检异常)——必须处理,否则报错
​ 2.1.1----IOException
​ 2.1.1.1-----FileNotFoundException
​ 2.1.2-----ClassNotFoundException
​ 2.2------运行时异常(unchecked,非受检异常,RuntimeException)——编译时不报错
​ 2.2.1-----NullPointerException
​ 2.2.2-----ArrayIndexOutOfBoundsException
​ 2.2.3-----ClassCastException
​ 2.2.4-----NumberFormatException
​ 2.2.5-----InputMismatchException
​ 2.2.6-----ArithmeticException

编译时异常:执行javac.exe命名时,可能出现的异常(必须先throws或者try-catch-finally处理)
运行时异常:执行java.exe命名时,出现的异常

2.关于异常对象的产生:

1.系统自动生成的异常对象

2.手动的生成一个异常对象,并抛出(throw)

3.异常的处理方式:

① try-catch-finally ② throws

异常处理方式一:主动处理异常

try-catch-finally

try{
    //可能出现异常的代码

}catch(异常类型1 变量名1){
    //处理异常的方式1
}catch(异常类型2 变量名2){
    //处理异常的方式2
}catch(异常类型3 变量名3){
    //处理异常的方式3
}finally{
    //一定会执行的代码
}

try-catch-finally说明:
1.finally是可省的

2.使用try将可能出现异常代码包装起来,在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,根据此对象的类型,去catch中进行匹配

3.一旦try中的异常对象匹配到某一个catch时,就进入catch中进行异常的处理。

​ 一旦处理完成,就跳出当前的try-catch结构(在没写finally的情况。继续执行其后的代码)

4.catch中的异常类型如果没子父类关系,则谁声明在上,谁声明在下无所谓。

catch中的异常类型如果满足子父类关系,则要求子类一定声明在父类的上面。否则,报错

5.常用的异常对象处理的方式: ① String getMessage() ② printStackTrace()

6.try结构中声明的变量,在出了try结构以后,就不能再被调用

7.try-catch-finally结构可以嵌套

finally的说明:

1.finally是可省的

2.finally中声明的是一定会被执行的代码。即使catch中又出现异常了,try中return语句,catch中return语句等情况。

3.像数据库连接、输入输出流、网络编程Socket等资源,JVM是不能自动的回收的,我们需要自己手动的进行资源的释放。此时的资源释放,就需

要声明在finally中。

异常处理方式二:抛出异常

  1. throws + 异常类型

    "throws + 异常类型"写在方法的声明处。指明此方法执行时,可能会抛出的异常类型。

    一旦当方法体执行时,出现异常,仍会在异常代码处生成一个异常类的对象,此对象满足throws后异常类型时,就会被抛出。

    异常代码后续的代码,就不再执行!

  2. throw new xxxException

    业务代码中可以做一定判断,不符合if条件,就手动的throw一个异常类的对象

对比两种处理方式

try-catch-finally:真正的将异常给处理掉了。

throws的方式只是将异常抛给了方法的调用者。并没真正将异常处理掉。

体会开发中应该如何选择两种处理方式?

1.如果父类中被重写的方法没throws方式处理异常,则子类重写的方法也不能使用throws,

​ 意味着如果子类重写的方法中异常,必须使用try-catch-finally方式处理。

2.执行的方法a中,先后又调用了另外的几个方法,这几个方法是递进关系执行的。

​ 我们建议这几个方法使用throws的方式进行处理。而执行的方法a可以考虑使用try-catch-finally方式进行处理。

补充:
方法重写的规则之一:子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型

4.自定义异常

如何自定义异常类?

1.继承于现的异常结构:RuntimeException 、Exception等

2.提供全局常量:serialVersionUID (每个异常类都需要有自己的版本号)

3.提供重载的构造器

public class MyException extends Exception{
    static final long serialVersionUID = -7034897193246939L;
    public MyException(){
    }
    public MyException(String msg){
        super(msg);
    }
}

5.带参数的try(){}语法

1.语法说明

java7中的新概念,try后面加括号,括号内可以写是使用的资源(创造对象)。
带资源的try语句(try-with-resource)的最简形式为:

try(Resource res = xxx)//可指定多个资源
{
    work with res
}

说明:

try块退出时,会自动调用res.close()方法,关闭资源。

不用写一大堆finally来关闭资源,所有实现Closeable的类声明都可以写在里面,最常见于流操作,socket操作,新版的httpclient也可以;

注意:try()的括号中可以写多行声明,每个声明的变量类型都必须实现AutoCloseable接口,用分号隔开,可以同时关闭多个流

2.Java7之前与之后写法对比

Java7之前:没有这个语法之前,流操作一般是这样写的:

InputStream is = null;
OutputStream os = null;
try {
    //...
} catch (IOException e) {
    //...
}finally{
    try {
        if(os!=null){
            os.close();
        }
        if(is!=null){
            is.close();
        }
    } catch (IOException e2) {
        //...
    }
}  

Java7之后

try(
    InputStream is = new FileInputStream("...");
    OutputStream os = new FileOutputStream("...");
){
    //...
}catch (IOException e) {
    //...
}

3.javap反编译后的理解

其实只看这个,不是很理解到底是如何实现的,那就直接看反编译的class就行了(Idea就是好)

Test代码

public static void copy(String src, String dst) throws IOException {
    try (InputStream in = new FileInputStream(src);
         OutputStream out = new FileOutputStream(dst)
        ) {
        byte[] buff = new byte[1024];
        int n;
        while ((n = in.read(buff)) >= 0) {
            out.write(buff, 0, n);
        }
    }
}

public static void testHHH() throws Exception {
    try (HHH h = new HHH()) {
        h.hhh();
    }
}

反编译后的代码

public static void copy(String src, String dst) throws IOException {
    InputStream in = new FileInputStream(src);
    Throwable var3 = null;
    try {
        OutputStream out = new FileOutputStream(dst);
        Throwable var5 = null;

        try {
            byte[] buff = new byte[1024];

            int n;
            while((n = in.read(buff)) >= 0) {
                out.write(buff, 0, n);
            }
        } catch (Throwable var29) {
            var5 = var29;
            throw var29;
        } finally {
            if (out != null) {
                if (var5 != null) {
                    try {
                        out.close();
                    } catch (Throwable var28) {
                        var5.addSuppressed(var28);
                    }
                } else {
                    out.close();
                }
            }

        }
    } catch (Throwable var31) {
        var3 = var31;
        throw var31;
    } finally {
        if (in != null) {
            if (var3 != null) {
                try {
                    in.close();
                } catch (Throwable var27) {
                    var3.addSuppressed(var27);
                }
            } else {
                in.close();
            }
        }

    }
}
public static void testHHH() throws Exception {
    HHH h = new HHH();
    Throwable var1 = null;
    try {
        h.hhh();
    } catch (Throwable var10) {
        var1 = var10;
        throw var10;
    } finally {
        if (h != null) {
            if (var1 != null) {
                try {
                    h.close();
                } catch (Throwable var9) {
                    var1.addSuppressed(var9);
                }
            } else {
                h.close();
            }
        }

    }
}

使用try-with-resources的目的,也是要保证资源的关闭(继承的AutoCloseable接口有close()抽象方法),即使关闭失败,也要成功返回异常

posted on 2022-03-06 21:43  freyhe  阅读(35)  评论(0编辑  收藏  举报