舔砖加瓦(java)之异常

2 篇文章 0 订阅
1 篇文章 0 订阅

添砖加瓦(java)

java异常

前言:

大家好我是kdy丶

一丶异常的概述和体系结构:

1丶异常的概述:

异常:在Java语言中,将程序执行中发生的不正常情况称为“异常”。

异常分为两种情况:Error和Exception。Throwable是他们的父类

1丶Error
就是jvm虚拟机无法处理的问题,通常情况下我们不能用针对性代码进行处理

例:
在这里插入图片描述

我们也可以看出这就是我们平常敲代码时候出现的错误。

2丶Exception
其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。

例:

public class demo01 {
    public static void main(String[] args) {
        int a=10;
        int b=0;
        System.out.println(a/b);
    }

}

在这里插入图片描述
这种 其实是属于运行期异常。

2丶异常的体系结构:

java.lang.Throwable是Error和Exception类的父类

java.lang.Error:一般不编写针对性的代码进行处理。

java.lang.Exception:可以进行异常的处理:

编译时异常(checked)

IOException
FileNotFoundException
ClassNotFoundException

运行时异常(unchecked,RuntimeException):

NullPointerException
ArrayIndexOutOfBoundsException
ClassCastException
NumberFormatException
InputMismatchException
ArithmeticException

在这里插入图片描述

其中蓝色图片的部分为非受检(unchecked)异常,红色的部分为受(checked)异常。受检异常就是在编译器就需要检查,非受检就是在运行期需要检查。

二丶异常的处理:

异常的处理主要有两种方法:

1丶try-catch-finally
2丶throws

Java提供的是异常处理的"抓抛"模型:

抛":程序在正常执行的过程中,一旦出现异常,就会在异常代码处生成一个对应异常类的对象。并将此对象抛出。 一旦抛出对象以后,其后的代码就不再执行。(异常对象的产生:1丶系统自动生成的异常对象2丶手动的生成一个异常对象,并抛出(throw))
“抓”:可以理解为异常的处理方式:1丶 try-catch-finally 2丶 throws

1丶处理方式一:try-catch-finally

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

}catch(异常类型1 变量名1){
//处理异常的方式1
}catch(异常类型2 变量名2){
//处理异常的方式2
}catch(异常类型3 变量名3){
//处理异常的方式3
}

finally{
//一定会执行的代码
}

public class demo02 {
     @Test
    public void test1(){
        int a=10;
        int b=0;
        System.out.println(a/b);
    }
}

运行结果:
在这里插入图片描述
我们可以看见由于分母为0,所以报了异常,但是我们要怎么处理这个异常呢?(finally可写可不写,看个人需要)

public class demo02 {
    @Test
    public void test1(){
        int a=10;
        int b=0;
        try {
            System.out.println(a/b);
        } catch (ArithmeticException e) {
            e.printStackTrace();
        }finally {
            System.out.println("分母不能为0");
        }

    }

}

运行结果:
在这里插入图片描述

在这里可能有人会说,这即使做异常处理,也和处理没啥区别啊,这有啥用?

由于运行时异常比较常见,所以我们通常就不针对运行时异常编写try-catch-finally了。针对于编译时异常,我们说一定要考虑异常的处理。

其实这就是编译时异常和运行时异常的差别,在我们运行时异常的时候,通常情况下,我们是不需要做特定的异常处理的,只有在编译器异常的时候才做处理。

我们看下这段代码:
在这里插入图片描述
我们可以看见这就是最常见的编译器出现异常的程序,

改正后:

public class demo03 {
    @Test
    public void test()  {
        File file = new File("kdy");
        FileInputStream fileInputStream=null;
        try {
            fileInputStream = new FileInputStream(file);

                int data = fileInputStream.read();
            while(data!=-1){
                    System.out.print((char) data);
                    data = fileInputStream.read();
                }

            } catch(FileNotFoundException e){
                e.printStackTrace();
            } catch(IOException e){
                e.printStackTrace();
            }finally {

            try {
                if (fileInputStream!=null)
                fileInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        }

改正之后编译就会通过,可是运行期异常会不会通过呢?
blog.csdnimg.cn/20210306162554980.png)

我们可以看见运行期出现了异常,这是以为本包所制定的路径上根本没有这个文件,所以会抛出这个异常。

所以当我们使用try-catch-finally处理编译时异常,虽然程序在编译时就不再报错,但是运行时仍可能报错。相当于我们使用try-catch-finally将一个编译时可能出现的异常,延迟到运行时出现。

就像上面那个运行期异常的例子一样,虽然编译期过了,但是运行期,没有过,要想运行,其实实质上就是要修改代码。

2丶finally关键字的使用:

finally关键字

1丶捕获异常的最后一步是通过finally语句为异常处理提供一个统一的出口,使得在控制流转到程序的其它部分以前,能够对程序的状态作统一的管理。
2丶不论在try代码块中是否发生了异常事件,catch语句是否执行,catch语句是否有异常,catch语句中是否有return,finally块中的语句都会被执行。
3丶像数据库连接、输入输出流、网络编程Socket等资源,JVM是不能自动的回收的,我们需要自己手动的进行资源的释放。此时的资源释放,就需要声明在finally中。

我们用代码说明一下:(用这个只是举个例子,单元测试类是只能用void修饰)
在这里插入图片描述
我们看刚才那一段代码:我们可以看见我只是改变了一下test这个方法的返回值为int,但是我在try{}代码块中return是不可以的,因为我们不能保证程序是否会异产生异常,如果产生异常,代码就不会再执行下去。所以我们不能在try中return。所以我们最好是在finally中return,因为finally这个代码块是必须执行的!

我们在看一下这个finally代码块的这个功能点的体现:

     @Test
    public void test2(){
        int a=10;
        int b=0;
            try {
                System.out.println(a/b);
            } catch (Exception e) {
                int arr[]=new int[5];
                arr[5]=5;
            }

            System.out.println("kdy");
        }

运行结果:
在这里插入图片描述

我们看这段代码,如果我们在catch编写一段有异常的代码,那么程序爆出异常,而不往下执行。

但是如果我们在在finally代码块中执行:

       @Test
    public void test2(){
        int a=10;
        int b=0;
            try {
                System.out.println(a/b);
            } catch (Exception e) {
                int arr[]=new int[5];
                arr[5]=5;
            }finally {
                System.out.println("kdy");
            }


        }

运行结果:
在这里插入图片描述
我们可以看见kdy是输出来了。

所以我们总结一下:

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

3丶 处理方式二:throws

1丶如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进处理,而由该方法的调用者负责处理。

2丶在方法声明中用throws语句可以声明抛出异常的列表throws后面的异常类型可以是方法中产生的异常类型也可以是它的父类

格式举例:
public void sta() throws Exception{……}

我们用代码说明一下:
在这里插入图片描述

我们可以看见,这是有错误的,为什么会报错,我明明是处理了异常?
在这里插入图片描述

我们可以看出编译器给出的提示,明显是还要对此方法进行处理。
在这里插入图片描述
运行结果:
在这里插入图片描述

我们可以看到这是完全可以运行的。所以我们不难发现throws不是直接的将异常处理掉,而是抛出给方法的调用者。真正能解决异常的还得是try-catch

我们在看这一段代码:

public class demo05 {
    public static void main(String[] args) {
        try {
            gr();
        } catch (IOException e) {
            System.out.println("4444");
        }
    }

    public static void gr() throws IOException {
        File file=new File("D:\\Users\\a\\java复习\\异常\\src\\异常概述\\kdy1.txt");
        FileInputStream fileInputStream=new FileInputStream(file);
        int data=fileInputStream.read();
        while (data!=-1){
            System.out.println((char) data);
            data=fileInputStream.read();
        }
        fileInputStream.close();
        System.out.println("kdy");
    }

运行结果:
在这里插入图片描述
我们可以看见在最后面的输出语句并没有执行,这也就以为着,一旦异常抛出,出现异常后面的代码就不会执行。

总结下来我们看一下两个处理方法的区别:

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

那我们这两种方式在什么情况下使用呢?
我们都知道子类的异常是不能大于父类的。

1丶所以如果父类中被重写的方法没throws方式处理异常,则子类重写的方法也不能使用throws,意味着如果子类重写的方法中异常,必须使用try-catch-finally方式处理。
2丶 执行的方法a中,先后又调用了另外的几个方法,这几个方法是递进关系执行的。我们建议这几个方法使用throws的方式进行处理。而执行的方法a可以考虑使用try-catch-finally方式进行处理。

三丶手动抛出异常对象和自定义异常:

1丶手动抛出异常对象

例:

public class demo07 {
    public static void main(String[] args) throws Exception {
        demo07 d=new demo07();
        d.test1(-1);
    }
    public void test1(int a) throws Exception {
        if (a>0){
            System.out.println(a);
        }else {
          throw new Exception("不能输入负数");
        }
    }
}

运行结果:
在这里插入图片描述
我们通常使用 throw new 异常()抛出一个异常类的对象。

throw和throws就差一个s,他两有什么不同呢?
其实不能说不同,可以说毫不相干:

throw 和 throws区别:
throw 表示抛出一个异常类的对象,生成异常对象的过程。声明在方法内。
throws 属于异常处理的一种方式,声明在方法的声明处。

2丶自定义异常:

自定义的异常一般分为三部:

1丶继承于现的异常结构:RuntimeException 、Exception等
2丶提供全局常量:serialVersionUID
3丶提供重载的构造器

我们定义的全局常量是不可以改变的,也是识别一个异常的标识。

例:

public class MyException extends RuntimeException {
    static final long serialVersionUID = -7034897193246939L;//全局常量
    public MyException(){
    }
    public MyException(String msg){
        super(msg);
    }
}

之后我们用我们自己定义的异常类来实现刚刚上面手动抛出的代码:

public class demo07 {
    public static void main(String[] args) throws RuntimeException {
        demo07 d=new demo07();
        d.test1(-1);
    }
    public void test1(int a) throws RuntimeException {
        if (a>0){
            System.out.println(a);
        }else {
          throw new MyException("不能输入负数");
        }
    }
}

运行结果:
在这里插入图片描述
我们可以看出,这是合理的。

四丶总结:

今天整理的java异常。希望大家能学到,同时也是自己重温知识的过程,我每天都会整理javase的基础知识分享给大家,完善自己。如果哪方面有问题,还请指正,期待大家的评论和关注,最后送给大家也送给自己一句话:真正的大师永远都怀着一颗学徒的心。

                                                                                              ——我是kdy丶,一个未来的java程序员 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值