Java异常

异常的作用

异常的引入提高了程序的健壮性.当程序运行出现意外情形时,系统会自动生成一个Exception对象来通知程序,从而提高容错性.先来看异常的使用方式和作用.

public class MainTest {
    public static void main(String[] args) {
        int a = 10;
        int b = 0;

        //这里除数是0,会产生异常,因为我们没有处理,会导致JVM崩掉
        int c = a / b;
        System.out.println(c + "");
    }
}

运行会发现JVM崩掉

Exception in thread "main" java.lang.ArithmeticException: / by zero
    at com.company.eric.Exception.MainTest.main(MainTest.java:11)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Process finished with exit code 1   

使用异常处理

public class MainTest {
    public static void main(String[] args) {
        try {
            int a = 10;
            int b = 0;

            //这里除数是0,会产生异常,因为我们没有处理,会导致JVM崩掉
            int c = a / b;
            System.out.println(c + "");
        }catch (ArithmeticException e){
            System.out.println("出现了算数错误");
            e.printStackTrace();
        }
    }
}

JVM正常退出,从Process finished with exit code 0可以看出

出现了算数错误
java.lang.ArithmeticException: / by zero
    at com.company.eric.Exception.MainTest.main(MainTest.java:13)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

Process finished with exit code 0

异常的引入可以让程序即使出现了错误,也可以运行,不至于让JVM崩掉.程序中出现的有些小错误是不影响程序的整体运行的,我们可以对异常进行捕获和处理,不让程序崩掉.

Java异常体系结构

Java异常类层次结构图

  • Error 是程序无法处理的错误,比如OutOfMemoryError、ThreadDeath等.这些异常发生时,Java虚拟机(JVM)一般会选择线程终止.
  • Exception 又分为非运行时异常(Checked exception)和运行时异常(Runtime exception)
  • Checked exception 必须要对其进行处理,否则无法通过编译。处理方式可以用try catch捕获或将其继续抛出
  • Runtime exception 可以对其进行处理,也可以不处理。

异常处理的一般结构

1.捕获异常

    try
    {
         // 可能发生异常的代码
        // 如果发生了异常,那么异常之后的代码都不会被执行
    }
    catch (Exception e)
    {
        // 异常处理代码
    }
    finally
    {
        // 不管有没有发生异常,finally语句块都会被执行
    }
  • try语句块,表示要尝试运行代码,try语句块中代码受异常监控,其中代码发生异常时,会抛出异常对象。
  • catch语句块会捕获try代码块中发生的异常并在其代码块中做异常处理,catch语句带一个Throwable类型的参数
  • 表示可捕获异常类型。当try中出现异常时,catch会捕获到发生的异常,并和自己的异常类型匹配,若匹配,则执行catch块中代码,并将catch块参数指向所抛的异常对象。catch语句可以有多个,用来匹配多个中的一个异常,一旦匹配上后,就不再尝试匹配别的catch块了。通过异常对象可以获取异常发生时完整的JVM堆栈信息,以及异常信息和异常发生的原因等。
  • finally语句块是紧跟catch语句后的语句块,这个语句块总是会在方法返回前执行, 而不管是否try语句块是否发生异常。并且这个语句块总是在方法返回前执行。这是一个必定执行的语句块,除非JVM退出.
try、catch、finally三个语句块应注意的问题
  1. try、catch、finally三个语句块均不能单独使用,三者可以组成try…catch…finally、try…catch、try…finally三种结构,catch语句可以有一个或多个,finally语句最多一个.
  2. try、catch、finally三个代码块中变量的作用域为代码块内部,分别独立而不能相互访问。如果要在三个块中都可以访问,则需要将变量定义到这些块的外面。
  3. 多个catch块时候,只会匹配其中一个异常类并执行catch块代码,而不会再执行别的catch块,并且匹配catch语句的顺序是由上到下。
捕获Exception后可以调用的常用方法
  • getCause():返回抛出异常的原因。如果 cause 不存在或未知,则返回 null.
  • getMessage():返回异常的消息信息.
  • printStackTrace():对象的堆栈跟踪输出至错误输出流,作为字段 System.err 的值。

2.继续抛出

public class MainTest {
    public static void main(String[] args) throws FileNotFoundException {
        BufferedReader br = new BufferedReader(
                            new InputStreamReader(
                            new FileInputStream("test.txt")));
    }
}
  • throws关键字用于方法体外部的方法声明部分,用来声明方法可能会抛出某些异常.
  • throw关键字是用于方法体内部,用来抛出一个Throwable类型的异常.

自己在方法中用throw抛出异常,用throws来表明该方法可能抛出的异常

    public void demo() throws Exception {
        throw new Exception("测试throw抛出异常");
    }

异常的流程:

Created with Raphaël 2.1.0 程序出现错误,产生对应的Exception 是否被捕获? 按照自定义的方式进行处理 向上抛出该异常 上层收到该异常,继续按照是否被捕获的方式继续处理 是否被捕获? ...... ...... 直到JVM收到该异常,JVM也无法处理 JVM崩溃,程序退出 yes no yes no

异常的处理流程还是符合我们现实的生活的;当分配到一件任务时,先看你自己能不能处理,如果能处理的话就处理掉,不能则将任务交给你的上级,你的上级也按照这个判断方式处理;若一直得不到处理,最终交给了公司领导,领导也处理不了,公司关门,游戏结束,……..

自定义异常

尽管Java中有一些常见的异常,但是这些可能不满足我们的需求,我们需要定制自己的异常类

自定义的异常(这里使用的Checked Exception,所以必须对这些异常进行处理,否则不能通过编译)

public class MyException extends Exception{
    public MyException(){
        super();
    }

    public MyException(String message){
        super(message);
    }
}

编写程序时使用该异常,遇到错误手动抛出异常

public class RepeatMachine {
    public static void repeatMessage(String message) throws MyException {
        if (message == null) {
            throw new MyException("输入对象不能为Null");
        }
        System.out.println(message);
    }
}

使用携带抛出异常的类时要对异常进行处理

public class MainTest {
    public static void main(String[] args) {
        try {
            RepeatMachine.repeatMessage(null);
        } catch (MyException e) {
            System.out.println(e.getMessage());
        }
    }
}

输出结果

输入对象不能为Null

Process finished with exit code 0

这里演示使用的Runtime exception(即使不对异常进行处理,也可通过编译)

public class MyException extends RuntimeException{
    public MyException(){
        super();
    }

    public MyException(String message){
        super(message);
    }
}
public class RepeatMachine {
    public static void repeatMessage(String message){
        if (message == null) {
            throw new MyException("输入对象不能为Null");
        }
        System.out.println(message);
    }
}
public class MainTest {
    public static void main(String[] args) {
        try {
            RepeatMachine.repeatMessage(null);
        } catch (MyException e) {
            System.out.println(e.getMessage());
        }

        RepeatMachine.repeatMessage("My name is Eric");
    }
}

输出结果

输入对象不能为Null
My name is Eric

Process finished with exit code 0
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值