首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java——try catch finally异常的捕获及处理逻辑实例详解大全

Java——try catch finally异常的捕获及处理逻辑实例详解大全

作者头像
Winter_world
发布2020-09-25 10:26:50
2.4K0
发布2020-09-25 10:26:50
举报

异常处理是Java语言的相当大的优势,且很简单。

1、认识异常

异常指的是导致程序中断执行的一种指令流。一旦发生异常且没有正常处理的话,程序将中断执行。

【举例】:观察产生异常的代码

        System.out.println("AAAA");
        System.out.println("计算="+(10/0));
        System.out.println("BBBB");

以上代码发生异常,程序没有执行完毕,打印完AAAA后直接崩溃退出,这种情况是不能容忍的。

2、处理异常

可以使用try、catch、finally三个关键字组合,完成正在执行的异常处理,语法如下,catch可以写多个:

try {
    //有可能出现异常的语句
}catch (异常类型 对象){
    //异常处理
}catch (异常类型 对象){
    //异常处理
}finally {
    //异常的统一出口代码
}

以上语法,也有三种组合模式:try...catch、try...catch...finally、try...finally

【举例】:利用try...catch 实现异常的处理操作

        System.out.println("AAAA");
        try {
            int result = 10/0;
            System.out.println("计算="+result);
        }catch (ArithmeticException e){
            System.out.println(e);
        }
        System.out.println("BBBB");

以上,我们发现程序可以正常运行,不会造成崩溃,但是代码还是有些问题,打印出的异常信息不完整,没发定位到具体是哪一行代码出了问题,可以用异常对象e的 printStackTrace()方法进行信息打印。

【举例】:利用try...catch...finally 结构进行异常处理

System.out.println("AAAA");
        try {
            int result = 10/0;
            System.out.println("计算="+result);
        }catch (ArithmeticException e){
            e.printStackTrace();
        }finally {
            System.out.println("=========");
        }
        System.out.println("BBBB");

以上,我们发现,异常产生之后执行catch语句内容,而后处理异常完毕后继续执行finally代码。若没有产生异常呢?finally中的代码还会执行吗?答案是的,把10/0改为10/1观察打印结果:

一个try语句后可以写多个catch进行处理,如果异常正常处理,则最后的语句(try...catch...finally后的)会正常执行,若没有正常处理,则不会正常执行,但是finally中的语句无论怎样都会执行。

为了保证程序出现错误后可以正常执行完毕,可以采用多个catch处理,但是,实际出现的异常会是什么类型的,我们自己可能都不知道,如何保证写的catch都能cover所有异常呢?

3、异常处理流程

为了分析Java中的异常处理流程,先看两个异常类的继承结构:

java.lang.ArithmeticException

java.lang.NumberFormatException

java.lang.Object     java.lang.Throwable         java.lang.Exception                  java.lang.RuntimeException                         java.lang.ArithmeticException

java.lang.Object     java.lang.Throwable          java.lang.Exception               java.lang.RuntimeException                    java.lang.IllegalArgumentException                         java.lang.NumberFormatException

可以发现,所有的异常类都是 java.lang.Throwable的子类,现在观察下Throwable类:

public class Throwable extends Object implements Serializable

其是Object的子类,从JDK1.0开始提供,但是Throwable下有两个子类,因此,开发中基本不会考虑Throwable处理。这里有个经典的面试题:

【面试题】:请解释Throwable下的Error和Exception的区别

  • Error:是在程序还未执行时出现的错误,一般指的是JVM出错,用户无法处理;
  • Exception:指的是程序运行中出现的异常,异常处理都是针对此类型完成的。

因此,以后的开发中,异常处理能够处理 的最大父类就是Exception。

下面根据以上分析结论,分析下异常的处理流程:

  • 1)程序产生异常后,JVM自动根据异常类型,实例化一个指定的异常类对象;
  • 2)程序判断当前代码中是否存在异常的处理逻辑,若没有,则交由JVM自动处理,方式为:输出异常信息,中断程序执行。
  • 3)若程序中存在异常处理,则try语句捕获该异常类的实例化对象;
  • 4)捕获到的异常类实例化对象,要与catch中的异常类型依次匹配;
  • 5)若catch匹配了异常类型,则使用相应代码进行处理,随后执行finally,若没有匹配,则直接跳转到finally语句;
  • 6)执行完finally后,要判断该异常是否处理过,若处理过,则继续执行后续代码,否则,交由JVM进行默认异常处理。

通过上述分析,可发现,catch匹配异常,和方法传递很类似,安按照对象向上转型的原则,左右的子类对象都可以用父类接收,所以,实际上都可以用Exception进行处理。

实际开发中,如果开发团队有明确要求,则异常进行分开处理(便于定位查询是出了什么错误),若要求不明确,则使用Exception进行处理是最方便的。

4、throws关键字

执行某些代码时,用户该如何知道会产生哪些异常?Java中的throws关键字,明确的告诉用户执行哪一个方法时有可能会产生哪些异常,该关键字主要用于方法的声明处。

【举例】:观察throws关键字

class MyMath{
    public static int div(int x, int y) throws Exception{
        return x/y;
    }
}

以上div方法中,要想执行该语句,就必须要进行异常的处理,此时编译无法通过。若程序中使用了throws声明,就必须强制使用try...catch进行异常处理操作。

使用throws后有一个传递的问题,主方法也是一个方法,所以主方法也可以使用throws,此时主方法不进行异常处理,而是交给被调用处处理。主方法之上是交由JVM默认处理,所以一般来说,Java代码主方法中应该把异常全部处理完成。

5、throw关键字

目前所有的异常对象都是由Java进行实例化对象的,我们处理的只是捕获异常对象,但是Java中允许用户自己去实例化异常类对象,若要抛出这个对象,就要用关键字throw。

【举例】:手工抛出异常

以上直接手工抛出异常,编译不通过,只要出现了throw,就表示代码产生了异常,此时只能:或者方法上使用throws继续抛出,或者手工异常处理try...catch。

        try {
            throw new Exception("我跑出的异常");
        } catch (Exception e) {
            e.printStackTrace();
        }

【面试题】:情请解释throw与throws的区别?

  • throw在方法体中使用,表示手工抛出一个异常类的实例化对象;
  • throws在方法的声明中使用,表示此方法调用时必须明确进行异常的处理;

6、异常处理模型

对于异常的处理已经学习过了:try、catch、finally、throw、throws这些关键字,finally、throw看似没什么用,但是用的时候一般都是一起用的。举个栗子,看下非常重要的异常处理模型。

假设定义一个除法计算的方法,要求:

  • 计算前可以打印提示信息;
  • 计算完成后可以打印提示信息;
  • 除法操作出了问题,要交给被调用处处理;
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        try {
            System.out.println(MyMath.div(10,0));
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

class MyMath{
    public static int div(int x, int y) throws Exception{//交给被调用处处理
        int result = 0;
        System.out.println("计算开始");
        result = x/y;
        System.out.println("计算结束");
        return result;
    }
}

以上程序输出,没有输出 计算结束,因为result=x/y  抛出异常,在被调用处进行处理,程序就over了。

【举例】:加入异常控制(非常重要的异常处理模型)

class MyMath{
    public static int div(int x, int y) throws Exception{//交给被调用处处理
        int result = 0;
        System.out.println("计算开始");
        try{
            result = x/y;
        }catch (Exception e){
            e.printStackTrace();
            throw e;//继续向上抛出异常
        }finally {
            System.out.println("计算结束");
        }
        return result;
    }
}

实际开发中,一定会牵扯到资源的使用,例如:文件、数据库,数据库操作前一定要打开,关闭后一定要关闭。但是以上给出的异常处理模型可以简化:try...finally,但是这种不太标准,不建议使用。

class MyMath{
    public static int div(int x, int y) throws Exception{//交给被调用处处理
        int result = 0;
        System.out.println("计算开始");
        try{
            result = x/y;
        }finally {
            System.out.println("计算结束");
        }
        return result;
    }
}

7、RuntimeException类

观察如下代码:

        int num = Integer.parseInt("10");
        System.out.println(num*num);

运行OK,但是,打开Integer类中的parseInt()方法来看:

public static int parseInt(String s) throws NumberFormatException

方法声明使用了throws关键字,但是我们 程序代码中没有进行异常处理,也能编译通过,运行正常。WHY???先观察下NumberFormatException类的继承结构。NumberFormatException 是RuntimeException的子类,所以该异常属于选择性处理,即使不处理,程序编译时也不会崩溃,但是执行时会出错。

java.lang.Object     java.lang.Throwable          java.lang.Exception               java.lang.RuntimeException                    java.lang.IllegalArgumentException                         java.lang.NumberFormatException

【面试题】:请解释Exception 与RuntimeException的子类?

  • RuntimeException是Exception的子类;
  • Exception定义的异常都需要进行强制性处理,但RuntimeException下子类在编写代码时不需要进行强制处理,由用户自己选择,若用户不处理,产生异常时交由JVM进行异常处理。

【面试题】:请举出常见的RuntimeException 异常?

  • ArithmeticException、NullPointerException、ClassCastException、NumberFormatException。

8、断言assert

JDK1.4开始增加了新的关键字,此部分内容了解即可,没什么用~ 断言,指的是在程序编写过程中确定代码执行到某行之后,数据一定是某个期待的内容。

【举例】:观察断言

        int num = 10;
        assert num==100 : "断言错误,num不是100";
        System.out.println(num);

以上,程序没有执行断言语句,对于断言,默认情况下是不会启用的,只有在程序运行时增加了一些配置参数,才会使用。

9、自定义异常类

Java中的异常类之中提供有大量的类型,但是这些提供的类型几乎都是语法有关的异常类型,缺少业务类型,比如:输入某个人的成绩,成绩超过100,那么就应该产生一个与之对应的异常处理。这样的异常需要开发者进行自定义,所以要用到自定义异常类。

对于异常类型主要有两种:Exception、RuntimeException。

【举例】:设计一个成绩的异常

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        double score = 101.1;
        if(score > 100){
            try {
                throw new ScoreException("成绩大于100分");
            } catch (ScoreException e) {
                e.printStackTrace();
            }
        }

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

10、总结

1)几种组合:try...catch、try...catch...finally...throws...throw;

2)RuntimeException与Exception的区别;

3)异常的处理流程:可以看成是引用对象的传递过程。

______________________________________________________________________________________

本文为博主原创文章,转载请注明出处,若本文对您有些许帮助,关注/评论/点赞就是对我最大的支持,多谢!

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-05-09 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、认识异常
  • 2、处理异常
  • 3、异常处理流程
  • 4、throws关键字
  • 5、throw关键字
  • 6、异常处理模型
  • 7、RuntimeException类
  • 8、断言assert
  • 9、自定义异常类
  • 10、总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档