关闭 x
IT技术网
    技 采 号
    ITJS.cn - 技术改变世界
    • 实用工具
    • 菜鸟教程
    IT采购网 中国存储网 科技号 CIO智库

    IT技术网

    IT采购网
    • 首页
    • 行业资讯
    • 系统运维
      • 操作系统
        • Windows
        • Linux
        • Mac OS
      • 数据库
        • MySQL
        • Oracle
        • SQL Server
      • 网站建设
    • 人工智能
    • 半导体芯片
    • 笔记本电脑
    • 智能手机
    • 智能汽车
    • 编程语言
    IT技术网 - ITJS.CN
    首页 » JAVA »深度分析Java中的异常与错误处理

    深度分析Java中的异常与错误处理

    2015-03-15 00:00:00 出处:王成委的博客
    分享

    Java中的异常处理机制已经比较成熟,我们的Java程序到处充满了异常的可能,如果对这些异常不做预先的处理,那么将来程序崩溃就无从调试,很难找到异常所在的位置。ITJS的这篇文章将探讨一下Java中异常与错误的处理方法,一起来看看。

    异常与错误:

    异常:

    在Java中程序的错误主要是语法错误和语义错误,一个程序在编译和运行时出现的错误我们统一称之为异常,它是VM(虚拟机)通知你的一种方式,通过这种方式,VM让你知道,你(开发人员)已经犯了个错误,现在有一个机会来修改它。Java中使用异常类来表示异常,不同的异常类代表了不同的异常。但是在Java中所有的异常都有一个基类,叫做Exception。

    错误:

    它指的是一个合理的应用程序不能截获的严重的问题。大多数都是反常的情况。错误是VM的一个故障(虽然它可以是任何系统级的服务)。所以,错误是很难处理的,一般的开发人员(当然不是你)是无法处理这些错误的,比如内存溢出。 和异常一样,在Java中用错误类来表示错误,不同的错误类代表了不同的错误。 但是在Java中所有的错误都有一个基类,叫做Error。

    综上,我们可以知道异常和错误最本质的区别就是异常能被开发人员处理而错误时系统本来自带的,一般无法处理也不需要我们程序员来处理。

    1.一个异常是在一个程序执行过程中出现的一个事件,它中断了正常指令的运行
    2.错误,偏离了可接受的代码行为的一个动作或实例

    异常的结构分类:

    1、运行时异常(未检查异常)
    2、编译时异常(已检查异常)

    运行异常即是RuntimeException;其余的全部为编译异常

    在Java中异常Exception和错误Error有个共同的父类Throwable。

    Error Exception

    runtimeException几个子类
    1、 java.lang.ArrayIndexOutOfBoundsException
    数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。

    2、java.lang.ArithmeticException
    算术条件异常。譬如:整数除零等。

    3、java.lang.NullPointerException
    空指针异常。当应用试图在要求使用对象的地方使用了null时,抛出该异常。譬如:调用null对象的实例方法、访问null对象的
    属性、计算null对象的长度、使用throw语句抛出null等等

    4、java.lang.ClassNotFoundException
    找不到类异常。当应用试图根据字符串形式的类名构造类,而在遍历CLASSPAH之后找不到对应名称的class文件时,抛出
    该异常。

    对异常的处理:

    try{}catch{}
    try{}catch{}finally{}无论有无异常finally代码块都会被执行
    try{}finally{}也是可以组合使用的但是catch{}finally{}不可以

    注意:在继承关系中,子类覆盖父类的方法,抛出异常的范围不能比父类更宽泛

    异常的使用

    在异常的使用这一部分主要是演示代码,都是我们平常写代码的过程中会遇到的(当然只是一小部分),抛砖引玉吗!

    例1. 这个例子主要通过两个方法对比来演示一下有了异常以后代码的执行流程。

    public static void testException1() {
    int[] ints = new int[] { 1, 2, 3, 4 };
    System.out.println("异常出现前");
    try {
    System.out.println(ints[4]);
    System.out.println("我还有幸执行到吗");// 发生异常以后,后面的代码不能被执行
    } catch (IndexOutOfBoundsException e) {
    System.out.println("数组越界错误");
    }
    System.out.println("异常出现后");
    }

    /*output:
    异常出现前
    数组越界错误
    常出现后
    */

    public static void testException2() {
    int[] ints = new int[] { 1, 2, 3, 4 };
    System.out.println("异常出现前");
    System.out.println(ints[4]);
    System.out.println("我还有幸执行到吗");// 发生异常以后,他后面的代码不能被执行
    }

    首先指出例子中的不足之处,IndexOutofBoundsException是一个非受检异常,所以不用try…catch…显示捕捉,但是我的目的是对同一个异常用不同的处理方式,看它会有什么不同的而结果(这里也就只能用它将就一下了)。异常出现时第一个方法只是跳出了try块,但是它后面的代码会照样执行的。但是第二种就不一样了直接跳出了方法,比较强硬。从第一个方法中我们看到,try…catch…是一种”事务性”的保障,它的目的是保证程序在异常的情况下运行完毕,同时它还会告知程序员程序中出错的详细信息(这种详细信息有时要依赖于程序员设计)。

    例2. 重新抛出异常

    public class Rethrow {
    public static void readFile(String file) throws FileNotFoundException {
    try {
    BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    System.err.println("不知道如何处理该异常或者根本不想处理它,但是不做处理又不合适,这是重新抛出异常交给上一级处理");
    //重新抛出异常
    throw e;
    }
    }
    public static void printFile(String file) {
    try {
    readFile(file);
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    }
    }
    public static void main(String[] args) {
    printFile("D:/file");
    }
    }

    异常的本意是好的,让我们试图修复程序,但是现实中我们修复的几率很小,我们很多时候就是用它来记录出错的信息。如果你厌倦了不停的处理异常,重新抛出异常对你来说可能是一个很好的解脱。原封不动的把这个异常抛给上一级,抛给调用这个方法的人,让他来费脑筋吧。这样看来,java异常(当然指的是受检异常)又给我们平添很多麻烦,尽管它的出发点是好的。

    例3. 异常链的使用及异常丢失

    ExceptionA,ExceptionB,ExceptionC
    public class ExceptionA extends Exception {
    public ExceptionA(String str) {
    super();
    }
    }
    public class ExceptionB extends ExceptionA {
    public ExceptionB(String str) {
    super(str);
    }
    }
    public class ExceptionC extends ExceptionA {
    public ExceptionC(String str) {
    super(str);
    }
    }

    异常丢失的情况:

    public class NeverCaught {
    static void f() throws ExceptionB{
    throw new ExceptionB("exception b");
    }
    static void g() throws ExceptionC {
    try {
    f();
    } catch (ExceptionB e) {
    ExceptionC c = new ExceptionC("exception a");
    throw c;
    }
    }
    public static void main(String[] args) {
    try {
    g();
    } catch (ExceptionC e) {
    e.printStackTrace();
    }
    }
    }
    /*
    exception.ExceptionC
    at exception.NeverCaught.g(NeverCaught.java:12)
    at exception.NeverCaught.main(NeverCaught.java:19)
    */

    为什么只是打印出来了ExceptionC而没有打印出ExceptionB呢 这个还是自己分析一下吧!

    上面的情况相当于少了一种异常,这在我们排错的过程中非常的不利。那我们遇到上面的情况应该怎么办呢 这就是异常链的用武之地:保存异常信息,在抛出另外一个异常的同时不丢失原来的异常。

    public class NeverCaught {
    static void f() throws ExceptionB{
    throw new ExceptionB("exception b");
    }
    static void g() throws ExceptionC {
    try {
    f();
    } catch (ExceptionB e) {
    ExceptionC c = new ExceptionC("exception a");
    //异常连
    c.initCause(e);
    throw c;
    }
    }
    public static void main(String[] args) {
    try {
    g();
    } catch (ExceptionC e) {
    e.printStackTrace();
    }
    }
    }
    /*
    exception.ExceptionC
    at exception.NeverCaught.g(NeverCaught.java:12)
    at exception.NeverCaught.main(NeverCaught.java:21)
    Caused by: exception.ExceptionB
    at exception.NeverCaught.f(NeverCaught.java:5)
    at exception.NeverCaught.g(NeverCaught.java:10)
    ... 1 more
    */

    这个异常链的特性是所有异常均具备的,因为这个initCause()方法是从Throwable继承的。

    例4. 清理工作

    清理工作对于我们来说是必不可少的,因为如果一些消耗资源的操作,比如IO,JDBC。如果我们用完以后没有及时正确的关闭,那后果会很严重,这意味着内存泄露。异常的出现要求我们必须设计一种机制不论什么情况下,资源都能及时正确的清理。这就是finally。

    public void readFile(String file) {
    BufferedReader reader = null;
    try {
    reader = new BufferedReader(new InputStreamReader(
    new FileInputStream(file)));
    // do some other work
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    } finally {
    try {
    reader.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }

    例子非常的简单,是一个读取文件的例子。这样的例子在JDBC操作中也非常的常见。(所以,我觉得对于资源的及时正确清理是一个程序员的基本素质之一。)

    Try…finally结构也是保证资源正确关闭的一个手段。如果你不清楚代码执行过程中会发生什么异常情况会导致资源不能得到清理,那么你就用try对这段”可疑”代码进行包装,然后在finally中进行资源的清理。举一个例子:

    public void readFile() {
    BufferedReader reader = null;
    try {
    reader = new BufferedReader(new InputStreamReader(
    new FileInputStream("file")));
    // do some other work
    //close reader
    reader.close();
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }

    我们注意一下这个方法和上一个方法的区别,下一个人可能习惯更好一点,及早的关闭reader。但是往往事与愿违,因为在reader.close()以前异常随时可能发生,这样的代码结构不能预防任何异常的出现。因为程序会在异常出现的地方跳出,后面的代码不能执行(这在上面应经用实例证明过)。这时我们就可以用try…finally来改造:

    public void readFile() {
    BufferedReader reader = null;
    try {
    try {
    reader = new BufferedReader(new InputStreamReader(
    new FileInputStream("file")));
    // do some other work
    // close reader
    } finally {
    reader.close();
    }
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }

    及早的关闭资源是一种良好的行为,因为时间越长你忘记关闭的可能性越大。这样在配合上try…finally就保证万无一失了(不要嫌麻烦,java就是这么中规中矩)。

    再说一种情况,假如我想在构造方法中打开一个文件或者创建一个JDBC连接,因为我们要在其他的方法中使用这个资源,所以不能在构造方法中及早的将这个资源关闭。那我们是不是就没辙了呢 答案是否定的。看一下下面的例子:

    public class ResourceInConstructor {
    BufferedReader reader = null;
    public ResourceInConstructor() {
    try {
    reader = new BufferedReader(new InputStreamReader(new FileInputStream("")));
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    }
    }
    public void readFile() {
    try {
    while(reader.readLine()!=null) {
    //do some work
    }
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    public void dispose() {
    try {
    reader.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }

    这一部分讲的多了一点,但是异常确实是看起来容易用起来难的东西呀,java中还是有好多的东西需要深挖的。

    上一篇返回首页 下一篇

    声明: 此文观点不代表本站立场;转载务必保留本文链接;版权疑问请联系我们。

    别人在看

    Destoon 模板存放规则及语法参考

    Destoon系统常量与变量

    Destoon系统目录文件结构说明

    Destoon 系统安装指南

    Destoon会员公司主页模板风格添加方法

    Destoon 二次开发入门

    Microsoft 将于 2026 年 10 月终止对 Windows 11 SE 的支持

    Windows 11 存储感知如何设置?了解Windows 11 存储感知开启的好处

    Windows 11 24H2 更新灾难:系统升级了,SSD固态盘不见了...

    小米路由器买哪款?Miwifi热门路由器型号对比分析

    IT头条

    Synology 对 Office 套件进行重大 AI 更新,增强私有云的生产力和安全性

    01:43

    StorONE 的高效平台将 Storage Guardian 数据中心占用空间减少 80%

    11:03

    年赚千亿的印度能源巨头Nayara 云服务瘫痪,被微软卡了一下脖子

    12:54

    国产6nm GPU新突破!砺算科技官宣:自研TrueGPU架构7月26日发布

    01:57

    公安部:我国在售汽车搭载的“智驾”系统都不具备“自动驾驶”功能

    02:03

    技术热点

    最全面的前端开发指南

    Windows7任务栏桌面下角的一些正在运行的图标不见了

    sql server快速删除记录方法

    SQL Server 7移动数据的6种方法

    SQL Server 2008的新压缩特性

    每个Java程序员必须知道的5个JVM命令行标志

      友情链接:
    • IT采购网
    • 科技号
    • 中国存储网
    • 存储网
    • 半导体联盟
    • 医疗软件网
    • 软件中国
    • ITbrand
    • 采购中国
    • CIO智库
    • 考研题库
    • 法务网
    • AI工具网
    • 电子芯片网
    • 安全库
    • 隐私保护
    • 版权申明
    • 联系我们
    IT技术网 版权所有 © 2020-2025,京ICP备14047533号-20,Power by OK设计网

    在上方输入关键词后,回车键 开始搜索。Esc键 取消该搜索窗口。