异常的捕获及处理

1. 异常的产生

异常是导致程序中断执行的一种指令流,异常一旦出现且没有对其进行合理的处理,程序就中断执行。
范例:不产生异常的代码

public class ExceptionDemo {
    public static void main(String[] args) {
        System.out.println("1.开始除法计算");
        System.out.println("2.计算 " + (10/2));
        System.out.println("3.结束除法计算");
    }
}

输出显示:

1.开始除法计算
2.计算 5
3.结束除法计算

范例:产生异常

public class ExceptionDemo {
    public static void main(String[] args) {
        System.out.println("1.开始除法计算");
        //此行代码产生异常
        System.out.println("2.计算 " + (10 / 0));     
        System.out.println("3.结束除法计算");
    }
}

输出显示:

1.开始除法计算
Exception in thread "main" java.lang.ArithmeticException: / by zero
    at ExceptionDemo.main(ExceptionDemo.java:5)

异常一旦发生,产生异常的语句及之后的语句都不再执行,默认输出异常信息后,程序自动结束执行。
我们要做的就是:即使出现了异常,也应该让程序正确的执行完毕。

2. 处理异常

如果想要进行异常的处理,在Java之中提供了三个关键字:try、catch、finally,而这三个关键字的使用语法如下:

//“[]” 表示有可能使用到
try {
    //有可能出现异常的语句
} [ catch(异常类型 对象){
    //异常处理
}catch(异常类型 对象){
    //异常处理
}...] [finally {
    //不管是否出现异常,都执行的代码
}]

范例:应用异常处理try...catch

public class ExceptionDemo {
    public static void main(String[] args) {
        System.out.println("1.开始除法计算");
        try {
            System.out.println("2.计算 " + (10 / 0));     
        } catch (ArithmeticException e){
            e.printStackTrace();
        }
        System.out.println("3.结束除法计算");
    }
}

输出显示:

1.开始除法计算
java.lang.ArithmeticException: / by zero
    at ExceptionDemo.main(ExceptionDemo.java:6)
3.结束除法计算

由于使用了异常处理,即使程序出现了异常,也可以正常的执行完毕。而且使用异常类中提供的printStackTrace()方法,可以完整的输出异常信息。
范例:使用try...catch...finally

public class ExceptionDemo {
    public static void main(String[] args) {
        System.out.println("1.开始除法计算");
        try {
            System.out.println("2.计算 " + (10 / 0));     
        } catch (ArithmeticException e){
            e.printStackTrace();
        } finally {
            System.out.println("不管是否有异常,都执行此语句!");
        }
        System.out.println("3.结束除法计算");
    }
}

输出显示:

1.开始除法计算
java.lang.ArithmeticException: / by zero
    at ExceptionDemo.main(ExceptionDemo.java:5)
不管是否有异常,都执行此语句!
3.结束除法计算

3. 异常的处理流程(核心)

首先观察两个异常类的继承结构:


1367514-b174472005c45bfb.png
观察两个异常类

观察可以发现所有的异常类都是Throwable的子类,而在Throwable下有两个子类:
Error 和 Exception

  • Error :指的是JVM错误,即:此时的程序还没有执行,用户还无法处理;
  • Exception :指的是程序运行中产生的异常,用户可以处理。

也就是所谓的异常处理指的就是所有的Exception以及它的子类异常。

面试题:Java中的异常处理流程

1367514-9d25e91d48cddd18.png
异常处理流程

范例:使用Exception处理异常

public class ExceptionDemo {
    public static void main(String[] args) {
        System.out.println("1.开始除法计算");
        try {
            int x = Integer.parseInt(args[0]);
            int y = Integer.parseInt(args[1]);
            System.out.println("2.计算 " + (x / y));
            System.out.println("**************");
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            System.out.println("不管是否有异常,都执行此语句!");
        }
        System.out.println("3.结束除法计算");
    }
}

所有的异常都使用了Exception进行处理,所以在程序之中不用再去关心到底使用哪一个异常。
注意:

  • 在编写多个catch捕获异常的时候,捕获范围大的异常一定要放在捕获异常范围小的异常之后,否则编译错误。
  • 虽然直接捕获Exception比较方便,但是这样也不好,因为这样所有的异常都会安装同一方式处理。

4. throws关键字

throws关键字主要用于方法声明上,指的是当方法之中出现异常后交由被调用处来进行处理。
范例:使用throws

class MyMath {
    //存在throws关键字,表示此方法里面产生的异常交给调用处处理
    public static int div(int x , int y) throws Exception {
        return x / y ;
    }
}
public class ThrowsDemo {
    public static void main(String[] args) {
        try {
            System.out.println(MyMath.div(10 , 2));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

调用了具有throws声明的方法之后,不管操作是否出现异常,都必须使用try...catch来进行异常的处理。

5. throw关键字

在程序之中直接使用throw手工抛出一个异常类的实例化对象。
范例:手工抛出异常

public class ThrowDemo {
    public static void main(String[] args) {
        try {
            throw new Exception("自己定义的异常");
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}

输出显示:

java.lang.Exception: 自己定义的异常
    at ThrowDemo.main(ThrowDemo.java:4)

面试题:throws 和 throw的区别

  • throws:在方法的声明上使用,表示此方法在调用时必须处理异常;
  • throw:指的是在方法中人为抛出一个异常类对象(这个异常类对象可能是自己实例化或是抛出已知存在)。

6. 重要的代码模型:异常的使用格式

需求:要求定义一个div()方法,在进行计算之前打印提示信息,计算结束也打印提示信息,如果在计算之中产生了异常,则交给被调用处进行处理。
范例:不出错的代码

class MyMath {
    public static int div(int x , int y) {
        int result = 0;
        System.out.println("*** 1. 计算开始 ***");
        result = x / y;
        System.out.println("*** 1. 计算结束 ***");
        return result;
        
    }
}
public class ThrowsDemo {
    public static void main(String[] args) {
            System.out.println(MyMath.div(10 , 2));
    }
}

但是以上代码中的除法操作不一定永远都正常完成,所以应该进行合理的处理。首先,如果方法出现异常,必须交由调用处处理,所以应该在方法上使用throws抛出

class MyMath {
    //存在throws关键字,表示此方法里面产生的异常交给调用处处理
    public static int div(int x , int y) throws Exception {
        int result = 0;
        System.out.println("*** 1. 计算开始 ***");
        result = x / y;
        System.out.println("*** 1. 计算结束 ***");
        return result;
        
    }
}
public class ThrowsDemo {
    public static void main(String[] args) {
        try {
            System.out.println(MyMath.div(10 , 2));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

如果以上代码真的出错,程序的有些内容就不执行了,所以修改如下:

class MyMath {
    //存在throws关键字,表示此方法里面产生的异常交给调用处处理
    public static int div(int x , int y) throws Exception {
        int result = 0;
        System.out.println("*** 1. 计算开始 ***");
        try {
            result = x / y;
        } catch (Exception e) {
            throw e;    //继续抛异常
        } finally {
            System.out.println("*** 1. 计算结束 ***");
        }
        return result;
    }
}
public class ThrowsDemo {
    public static void main(String[] args) {
        try {
            System.out.println(MyMath.div(10 , 0));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

输出显示:

*** 1. 计算开始 ***
*** 1. 计算结束 ***
java.lang.ArithmeticException: / by zero
    at MyMath.div(ThrowsDemo.java:7)
    at ThrowsDemo.main(ThrowsDemo.java:19)

7. RuntimeException 类

先观察一段代码:

public class RuntimeExceptionDemo {
    public static void main(String[] args) {
        int temp = Integer.parseInt("100");
        System.out.println(temp);   //输出100
    }
}

在看一下parseInt()方法的定义:
public static int parseInt(String s) throws NumberFormatException
此时parseInt()方法上抛出了NumberFormatException,按理说,应该进行强制性的异常捕获,但是现在并没有强制性操作,所以来看下NumberFormatException的继承结构:

java.lang.Object 
    java.lang.Throwable 
        java.lang.Exception 
            java.lang.RuntimeException → 运行时异常
                java.lang.IllegalArgumentException 
                    java.lang.NumberFormatException

在Java里面为了方便用户代码的编写,专门提供了RuntimeException类,其特征为:程序在编译的时候不会强制性要求用户处理异常,用户可以根据需求选择性的进行处理,如果没有处理又发生了异常,则交给JVM默认处理。

面试题:Exception 和 RuntimeException的区别?列举几个常见的RuntimeException子类:

  • Exception是RuntimeException的父类;
  • 使用Exception定义的异常必须要被处理,而RuntimeException的异常可以选择性处理:
  • 常见的RuntimeException:ArithmeticException、NullPointerException、ClassCastException。

8. assert关键字—断言(了解)

assert关键字是在JDK1.4的时候引入的,其主要的功能就是进行断言。断言:指的是程序执行到某行代码处判断是否是预期的结果。
范例:观察断言

public class AssertDemo {
    public static void main(String[] args) {
        int num = 10;
        //中间可能经过了多行代码操作num的内容
        //期望中的内容是20
        assert num == 20 : "num的内容不是20";
        System.out.println("num = " + num);
    }
}

正常执行输出显示:
num = 10
启用断言执行:java -ea AssertDemo

Exception in thread "main" java.lang.AssertionError: num的内容不是20
        at AssertDemo.main(AssertDemo.java:6)

9. 自定义异常

Java本身提供了大量的异常,但是这些异常实际工作中并不够去使用,所以就需要用户自定义异常类。如果开发自定义的异常类可以选择继承Exception或者RuntimeException类。
范例:定义AddException

class AddException extends Exception{
    public AddException(String msg) {
        super(msg);
    }
}

public class AddExceptionDemo{
    public static void main(String[] args) {
        int num = 20;
        try {
            if (num > 0) {  //出现错误,应该产生异常
                throw new AddException("数值传递过大");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

以上代码知识介绍自定义异常的形式,但是并不能说明自定义异常的实际使用。

总结

  1. Exception的父类是Throwable,但是在编写代码的时候尽量不要使用Throwable,因为Throwable类有子类Error,用户能处理的只有Exception类
  2. 异常处理的标准格式:try、catch、finally、throw、throws;
  3. RuntimeException与Exception的区别。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值