分享

Java 异常的捕获与处理详解(二)

 oldzhoua 2019-03-14

上一篇Java 异常的捕获与处理详解(一)讲了异常的产生、处理以及处理流程,接下来讲其他内容。

一、throws关键字

thrwos关键字主要是在方法定义上使用的,表示的是此方法之中不进行异常的处理,而交给被调用处处理。

例如:

class MyMath { public int div(int x, int y) throws Exception { return x / y; }}
  • 1
  • 2
  • 3
  • 4
  • 5

现在的div()方法之中抛了一个异常出来,表示所有的异常交给被调用处进行处理。

class MyMath {    public int div(int x, int y) throws Exception {        return x / y;    }}public class Test {    public static void main(String args[]) {        try {            System.out.println(new MyMath().div(10, 0));        } catch (Exception e) {            e.printStackTrace();        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

运行结果:

java.lang.ArithmeticException: / by zero at MyMath.div(Test.java:3) at Test.main(Test.java:10)
  • 1
  • 2
  • 3

注意: 在调用throws声明方法的时候,一定要使用异常处理操作进行异常的处理,这属于强制性的处理。

而主方法本身也属于方法,那么在主方法上也可以继续使用throws进行异常的抛出:

class MyMath {    public int div(int x, int y) throws Exception {        return x / y;    }}public class Test {    public static void main(String args[]) throws Exception {        System.out.println(new MyMath().div(10, 0));    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

运行结果:

Exception in thread 'main' java.lang.ArithmeticException: / by zero at MyMath.div(Test.java:3) at Test.main(Test.java:9)
  • 1
  • 2
  • 3

这时主方法将异常继续向上抛,交给JVM进行异常的处理,也就是采用默认的方式,输出异常信息,而后结束程序执行。

注意:在实际开发中,主方法不要加throws,因为程序如果有异常,我们也希望可以正常的结束。

二、throw关键字

之前所有异常类对象都是由JVM自动进行实例化操作的,用户也可以自己手工的抛出一个异常类实例化对象,就通过throw完成了。

public class Test {    public static void main(String args[]) {        try {            throw new Exception('自定义的异常');        } catch (Exception e) {            e.printStackTrace();        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

运行结果:

java.lang.Exception: 自定义的异常 at Test.main(Test.java:4)
  • 1
  • 2

小结:throw和throws的区别?

(1)throw:在方法体内使用,表示人为的抛出一个异常类对象(这个对象可可以是自己实例化的,也可以是已存在的);
(2)throws:在方法的声明上使用,表示在此方法中不进行异常的处理,而交给被调用处处理。

三、异常处理标准格式

我们有种感觉,finally和throw没有用处。现要求定义一个div()方法,这个方法有如下的一些要求:
(1)在进行除法操作之前,输出一行提示信息;
(2)在除法操作执行完毕后,输出一行提示信息;
(3)如果中间产生了异常,则应该交给被调用处来进行处理。

class MyMath {    // 出现异常要交给被调用处出,使用throws    public int div(int x, int y) throws Exception {        System.out.println('===== 计算开始 =====');         int result = 0;        try {            result = x / y; // 除法计算        } catch (Exception e) {            throw e; // 向上抛        } finally {            System.out.println('===== 计算结束 =====');         }        return result;    }}public class Test {    public static void main(String args[]) {        try {            System.out.println(new MyMath().div(10, 0));        } catch (Exception e) {            e.printStackTrace();        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

运行结果:

===== 计算开始 ========== 计算结束 =====java.lang.ArithmeticException: / by zero at MyMath.div(Test.java:7) at Test.main(Test.java:20)
  • 1
  • 2
  • 3
  • 4
  • 5

以上代码也可以做一些简化:

class MyMath {    // 出现异常要交给被调用处出,使用throws    public int div(int x, int y) throws Exception {        System.out.println('===== 计算开始 =====');         int result = 0;        try {            result = x / y; // 除法计算        } finally {            System.out.println('===== 计算结束 =====');        }        return result;    }}public class Test {    public static void main(String args[]) {        try {            System.out.println(new MyMath().div(10, 0));        } catch (Exception e) {            e.printStackTrace();        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

运行结果:

===== 计算开始 ========== 计算结束 =====java.lang.ArithmeticException: / by zero at MyMath.div(Test.java:7) at Test.main(Test.java:18)
  • 1
  • 2
  • 3
  • 4
  • 5

直接使用try…finally,不带有catch,那么就连处理的机会都没有了,所以不建议使用try…finally。标准格式是try…catch、finally、throws、throw一起使用。

四、RuntimeException类

先来观察一段代码

public class Test {    public static void main(String args[]) {        String str = '123';        int num = Integer.parseInt(str);        System.out.println(num * num);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

运行结果:

15129
  • 1
  • 2

这个程序就是将一个字符串变为了基本数据类型,而后执行乘法操作,但是下面来看一下parseInt()方法定义:

public static int parseInt(String s) throws NumberFormatException
  • 1

发现这个方法上抛出了一个NumberFormatException的异常,按照之前所讲,如果存在了throws,则必须使用try…catch进行处理,可是现在却没有强制要求处理,这是为什么呢?
来观察一下NumberFormatException的继承结构:

java.lang.Object |- java.lang.Throwable |- java.lang.Exception |- java.lang.RuntimeException |- java.lang.IllegalArgumentException |- java.lang.NumberFormatException
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

发现NumberFormatException属于RuntimeException的子类,而在Java之中明确规定:对于RuntimeException的异常类型,在编译的时候不会强制性的要求用户处理,用户可以根据需要有选择性的来进行处理,在开发之中,如果没有处理,那么出现异常之后将交给JVM默认进行处理。也就是说,RuntimeException的子异常类,可以由用户根据需要有选择性的来进行处理。

小结:RuntimeException和Exception的区别?请列举出几个常见的RuntimeException.

(1)RuntimeException是Exception的子类;
(2)Exception定义了必须处理的异常,而RuntimeException定义的异常可以选择性的进行处理。

常见的RuntimeException:
NumberFormatException、ClassCastException、NullPointerException、ArithmeticException、ArrayIndexOutOfBoundsException。

五、assert关键字(断言)

Java中断言指的是程序执行到某行之后,其结果一定是预期的结果,而在JDK 1.4之后增加了一个assert关键字。

两种语法形式:
(1)形式一:

assert condition;
  • 1

这里condition是一个必须为真(true)的表达式。如果表达式的结果为true,那么断言为真,并且无任何行动
如果表达式为false,则断言失败,则会抛出一个AssertionError对象。这个AssertionError继承于Error对象。

(2)形式二:

asser condition:expr;
  • 1

这里condition是和上面一样的,这个冒号后跟的是一个表达式,通常用于断言失败后的提示信息,说白了,它是一个传到AssertionError构造函数的值,如果断言失败,该值被转化为它对应的字符串,并显示出来。

使用断言:

public class Test {    public static void main(String args[]) {        int x = 10;        // 假设经过了若干操作        assert x == 30 : 'x的内容不是30';        System.out.println(x);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

默认情况下,Java之中的断言,不会在正常执行的代码中出现,如果要想启用断言,则应该增加-ea选项:

java -ea Test
  • 1

运行结果:

Exception in thread 'main' java.lang.AssertionError: x的内容不是30        at Test.main(Test.java:5)
  • 1
  • 2

六、自定义异常

在Java之中本身已经提供了大量的异常类型,但是在开发之中,这些异常类型还不能满足于开发的需要。所以在一些系统架构之中往往会提供一些新的异常类型,来表示一些特殊的错误,而这种操作就称为自定义异常类,而要想实现这种自定义异常类,那么可以让一个类继承Exception或RuntimeException。

class MyException extends Exception { // 自定义异常类 public MyException(String msg) { super(msg); }}public class Test { public static void main(String args[]) throws Exception { throw new MyException('自己的异常类'); }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

运行结果:

Exception in thread 'main' MyException: 自己的异常类    at Test.main(Test.java:9)
  • 1
  • 2

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多