iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > JAVA >你必须了解的java中的异常
  • 242
分享到

你必须了解的java中的异常

java 2014-09-11 07:09:56 242人浏览 绘本
摘要

一. 异常的定义(推荐:java视频教程)在《java编程思想》中这样定义 异常:阻止当前方法或作用域继续执行的问题。虽然java中有异常处理机制,但是要明确一点,决不应该用"正常"的态度来看待异常。绝对一点说异常就是某种意义上的错误,就是

一. 异常的定义(推荐:java视频教程

在《java编程思想》中这样定义 异常:阻止当前方法或作用域继续执行的问题。虽然java中有异常处理机制,但是要明确一点,决不应该用"正常"的态度来看待异常。绝对一点说异常就是某种意义上的错误,就是问题,它可能会导致程序失败。之所以java要提出异常处理机制,就是要告诉开发人员,你的程序出现了不正常的情况,请注意。

记得当初学习java的时候,异常总是搞不太清楚,不知道这个异常是什么意思,为什么会有这个机制?但是随着知识的积累逐渐也对异常有一点感觉了。举一个例子来说明一下异常的用途。

public class Calculator {
    public int devide(int num1, int num2) {
        //判断除数是否为0
        if(num2 == 0) {
            throw new IllegalArgumentException("除数不能为零");
        }
         
        return num1/num2;
    }
}

看一下这个类中关于除运算的方法,如果你是新手你可能会直接返回计算结果,根本不去考虑什么参数是否正确,是否合法(当然可以原谅,谁都是这样过来的)。但是我们应尽可能的考虑周全,把可能导致程序失败的"苗头"扼杀在摇篮中,所以进行参数的合法性检查就很有必要了。

其中执行参数检查抛出来的那个参数非法异常,这就属于这个方法的不正常情况。正常情况下我们会正确的使用计算器,但是不排除粗心大意把除数赋值为0。如果你之前没有考虑到这种情况,并且恰巧用户数学基础不好,那么你完了。但是如果你之前考虑到了这种情况,那么很显然错误已在你的掌控之中。

二. 异常扫盲行动

今天和别人聊天时看到一个笑话:世界上最真情的相依,是你在try我在catch。无论你发神马脾气,我都默默承受,静静处理。 大多数新手对java异常的感觉就是:try...catch...。没错,这是用的最多的,也是最实用的。我的感觉就是:java异常是从"try...catch..."走来。

首先来熟悉一下java的异常体系:

Throwable 类是 Java 语言中所有错误或异常的超类(这就是一切皆可抛的东西)。它有两个子类:Error和Exception。

Error:用于指示合理的应用程序不应该试图捕获的严重问题。这种情况是很大的问题,大到你不能处理了,所以听之任之就行了,你不用管它。比如说VirtualMachineError:当 Java 虚拟机崩溃或用尽了它继续操作所需的资源时,抛出该错误。好吧,就算这个异常的存在了,那么应该何时,如何处理它呢??交给JVM吧,没有比它更专业的了。

Exception:它指出了合理的应用程序想要捕获的条件。Exception又分为两类:一种是CheckedException,一种是UncheckedException。

这两种Exception的区别主要是CheckedException需要用try...catch...显示的捕获,而UncheckedException不需要捕获。通常UncheckedException又叫做RuntimeException。

我们常见的RuntimeExcepiton有IllegalArgumentException、IllegalStateException、NullPointerException、IndexOutOfBoundsException等等。对于那些CheckedException就不胜枚举了,我们在编写程序过程中try...catch...捕捉的异常都是CheckedException。io包中的IOException及其子类,这些都是CheckedException。

三. 异常的使用

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

例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("异常出现后");
    }
    
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();
            }
    }
 
}

为什么只是打印出来了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();
            }
    }
 
}

这个异常链的特性是所有异常均具备的,因为这个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中还是有好多的东西需要深挖的。

四. 异常的误用

对于异常的误用着实很常见,上一部分中已经列举了几个,大家仔细的看一下。下面再说两个其他的。

例1. 用一个Exception来捕捉所有的异常,颇有"一夫当关万夫莫开"的气魄。不过这也是最傻的行为。

public void readFile(String file) {
        BufferedReader reader = null;
        Connection conn = null;
        try {
            reader = new BufferedReader(new InputStreamReader(
                    new FileInputStream(file)));
            // do some other work
             
            conn = DriverManager.getConnection("");
            //...
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                reader.close();
                conn.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

从异常角度来说这样严格的程序确实是万无一失,所有的异常都能捕获。但是站在编程人员的角度,万一这个程序出错了我们该如何分辨是到底是那引起的呢,IO还是JDBC...所以,这种写法很值得当做一个反例。大家不要以为这种做法很幼稚,傻子才会做。我在公司实习时确实看见了类似的情况:只不过是人家没有用Exception而是用了Throwable。

例2. 这里就不举例子了,上面的程序都是反例。异常是程序处理意外情况的机制,当程序发生意外时,我们需要尽可能多的得到意外的信息,包括发生的位置,描述,原因等等。

这些都是我们解决问题的线索。但是上面的例子都只是简单的printStackTrace()。如果我们自己写代码,就要尽可能多的对这个异常进行描述。比如说为什么会出现这个异常,什么情况下会发生这个异常。如果传入方法的参数不正确,告知什么样的参数是合法的参数,或者给出一个sample。

例3. 将try block写的简短,不要所有的东西都扔在这里,我们尽可能的分析出到底哪几行程序可能出现异常,只是对可能出现异常的代码进行try。尽量为每一个异常写一个try...catch,避免异常丢失。

更多java知识请关注Java基础教程栏目。

--结束END--

本文标题: 你必须了解的java中的异常

本文链接: https://www.lsjlt.com/news/1762.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java中的异常你了解多少?
    目录 一.认识异常二.异常分类三.异常的分类1.编译时异常2.运行时异常 四.异常的处理1.LYBL:事前防御型2.EAFP:事后认错型 五.异常的抛出Throw==注意事项== 六.异常的捕获1.异常的捕获2.异常声明...
    99+
    2023-12-22
    java python 开发语言
  • Java开发者必须了解的NPM常用命令
    作为一名Java开发者,你是否经常使用NPM来管理你的前端依赖包呢?如果是的话,那么下面这些NPM常用命令一定会帮助你更加高效地开发和维护你的项目。 npm init 在创建一个新的项目时,你需要运行npm init命令来初始化一个p...
    99+
    2023-11-07
    npm 文件 二维码
  • 你必须了解的JavaScript中的属性描述对象详解(下)
    目录元属性valuewritableenumerableconfigurable存取器对象的拷贝控制对象状态Object.preventExtensions()Object.isEx...
    99+
    2022-12-22
    JavaScript属性描述对象 JavaScript属性描述 JavaScript属性
  • 你必须了解的JavaScript中的属性描述对象详解(上)
    目录属性描述对象Object.getOwnPropertyDescriptor()Object.getOwnPropertyNames()Object.defineProperty(...
    99+
    2022-12-22
    JavaScript属性描述对象 JavaScript属性描述 JavaScript属性
  • 学习MySQL必须了解的13个关键字,你get了吗?
    目录 1、三范式 2、字符集 3、自定义变量 4、选择优化的数据类型 (1)更小的 (2)更简单的 (3)尽量避免NULL 5、视...
    99+
    2023-08-20
    数据库 mysql sql
  • 你必须知道的python运维常用脚本!(
    github地址:https://github.com/opsonly, 上面是一个基于python3.7和django2.1的多人博客系统,喜欢的可以给个star~ 判断是否是一个目录 #!/usr/bin/env python3 #...
    99+
    2023-01-31
    你必须 脚本 常用
  • 一篇文章带你了解C++中的异常
    目录异常抛出异常基本操作自定义的异常类栈解旋异常接口声明异常变量的生命周期异常的多态c++的标准异常库编写自己的异常类总结异常 在c语言中,对错误的处理总是两种方法: 1,使用整型的...
    99+
    2024-04-02
  • Oracle数据类型大揭秘:你必须了解的知识点
    Oracle数据类型大揭秘:你必须了解的知识点,需要具体代码示例 Oracle作为世界领先的数据库管理系统之一,在数据存储和处理中扮演着重要的角色。在Oracle中,数据类型是非常重要...
    99+
    2024-03-07
    数据类型 oracle 知识点
  • 必须了解的Linux命令有哪些
    小编给大家分享一下必须了解的Linux命令有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!1.ls – Listls会列举出当前工作目录的...
    99+
    2023-06-16
  • 面试中必须了解的 Laravel 重定向问题
    作为一名 Laravel 开发者,在面试中必须了解 Laravel 重定向问题。在本文中,我们将讨论 Laravel 中的重定向问题,并提供一些实用的解决方案。 Laravel 重定向 重定向是 Web 开发中常用的一种技术,它将用户从一个...
    99+
    2023-10-09
    面试 laravel 重定向
  • Java:详解Java中的异常
    目录Java异常常见异常throw和throws的区别final、finally、finalize的区别总结Java异常 Java中的异常:又称例外,是一个在程序执行期间发生的事件,...
    99+
    2024-04-02
  • 一篇文章带你深入了解Java异常
    目录一.初识异常1.常见的异常类型<1>除以0<2>数组下标越界<3>访问null对象2.防御式编程<1>LBYL<2>E...
    99+
    2024-04-02
  • Java 程序员必须了解的计算机底层知识
    这期内容当中小编将会给大家带来有关Java 程序员必须了解的计算机底层知识,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。我们每个程序员或许都有一个梦,那就是成为大牛,我们或许都沉浸在各种框架中,以为框架就...
    99+
    2023-06-03
  • Java面试前必须了解的10个概念是什么
    这篇文章主要介绍“Java面试前必须了解的10个概念是什么”,在日常操作中,相信很多人在Java面试前必须了解的10个概念是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java面试前必须了解的10个概念...
    99+
    2023-06-17
  • 全面了解java异常
    目录异常的概念异常体系异常的分类异常产生的过程分析异常的处理抛出异常throw声明异常throws捕获异常try…catch捕获异常语法如何获取异常信息:finally代码块try ...
    99+
    2024-04-02
  • PHP开发者必须了解的Shell命令
    作为一名PHP开发者,除了掌握PHP语言的基本语法和常用函数外,还需要掌握一些Linux系统的基础知识和常用的Shell命令。Shell是Linux系统下的一种命令解释器,通过Shell命令可以实现很多系统操作和管理任务,对于PHP开发者...
    99+
    2023-11-01
    ide shell 存储
  • Java和JavaScript的异同,你真的了解吗?
    Java和JavaScript是两种非常常见的编程语言,它们在很多方面有着相似的特性,但它们也有着很多不同之处。在本文中,我们将探讨Java和JavaScript的异同,并且演示一些代码示例来帮助你更好地理解它们。 Java和JavaS...
    99+
    2023-10-24
    javascript http 重定向
  • Java的内存区域与内存溢出异常你了解吗
    目录1.运行时数据区域1.程序计数器(线程私有)2.Java虚拟机栈(线程私有)3.本地方法栈(线程私有)4.Java堆(线程共享)5.方法区(线程共享)6.运行时常量池2.对象是如...
    99+
    2024-04-02
  • MySQL必须了解的关键字有哪些
    本篇内容主要讲解“MySQL必须了解的关键字有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“MySQL必须了解的关键字有哪些”吧!1、三范式第一范式:每个表...
    99+
    2022-12-08
    mysql
  • Python异步编程技巧:Leetcode对象是你必须掌握的!
    随着互联网的发展,网络应用越来越复杂,对于开发人员而言,如何提高程序的并发性能成为了一个挑战。异步编程是解决这个问题的一个重要手段。Python是一门支持异步编程的语言,它提供了asyncio库来实现异步编程。本文将介绍一种Python异...
    99+
    2023-07-05
    leetcode 对象 异步编程
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作