当前位置: 首页 > 科技观察

说说Java中的异常与处理

时间:2023-03-22 00:56:11 科技观察

编程中异常错误在所难免。尤其是在学习某门语言的初期,看到异常的报错就抓耳挠腮。我经常开玩笑说1分钟的编程和1小时的错误修正。今天就让我们来看看什么是异常,如何合理处理!来看看异常和错误介绍中的基本概念吧!异常是指程序运行过程中出现的异常现象,例如用户输入错误、除数为零、要处理的文件不存在、数组下标越界等。异常机制的本质是当程序发生错误时程序安全退出的一种机制。在Java的异常处理机制中,引入了很多用于描述和处理异常的类,称为异常类。异常类定义包含了该类异常的信息和处理异常的方法。Java使用面向对象的方法来处理异常。处理过程:抛出异常:在执行方法时,如果发生异常,则该方法生成一个代表异常的对象,停止当前执行路径,并将异常对象提交给JRE。Catchtheexception:JRE??获取到异常后,会寻找相应的代码来处理异常。JRE查看方法的调用栈,从产生异常的方法开始回溯,直到找到对应的异常处理代码。我们来看看上面说的异常类是什么!事实上,所有异常对象都是从Throwable类的实例派生的。如果内置的异常类不能满足你的需求,你也可以创建自己的异常类。所有异常的根类都是java.lang.Throwable。看看它的家人长什么样。Throwable类下面主要是两个流派:Error和Exception。Error是程序无法处理的错误,表示应用程序运行出现严重问题,系统JVM已经处于不可恢复的崩溃状态。比如说内存溢出、线程死锁等系统问题。Exception是程序本身可以处理的异常。Exception类是所有异常类的父类,它的子类对应着各种可能发生的异常事件。通常Java异常可以分为:RuntimeException运行时异常CheckedExceptionChecked异常我们来研究一下这两种异常。RuntimeException和CheckedException的异同首先我们来看看什么是运行时异常。此类异常通常是由编程错误引起的,因此在编写程序时,并不需要使用异常处理机制来处理此类异常,但往往需要通过添加“逻辑处理”来避免此类异常.比如下面常见的异常:ArithmeticExceptionintb=0;System.out.println(1/b);//解决方法:if(b!=0){System.out.println(1/b);}NumberFormatException异常Stringstr="1234abcf";System.out.println(Integer.parseInt(str));//解决方法:Patternp=Pattern.compile("^\\d+$");Matcherm=p.matcher(str);if(m.matches()){//如果str匹配一个表示一个数字的正则表达式,它会被转换System.out.println(Integer.parseInt(str));}ClassCastExceptionAnimala=newDog();Catc=(Cat)a;//解决方案:if(ainstanceofCat){Catc=(cat)a;}这里再补充两点,让大家更好的理解java异常的机制和处理过程。方法抛出异常后,运行时系统会转而寻找合适的异常处理器(exceptionhandler)。潜在的异常处理程序是在发生异常时顺序保存在调用堆栈上的方法集合。当异常处理程序能够处理的异常类型与方法抛出的异常类型相匹配时,就是合适的异常处理程序。运行时系统从发生异常的方法开始,依次检查调用栈中的方法,直到找到合适的异常处理器的方法并执行。当运行时系统遍历调用堆栈而没有找到合适的异常处理程序时,运行时系统终止。同时,也意味着Java程序的终止。上面我们介绍了什么是运行时异常以及一些处理方法,下面我们就来看看什么是checkedexception吧!所有不属于RuntimeException的异常统称为CheckedException,也称为“已检查异常”,如IOException、SQLException等和用户自定义Exception异常。这种异常必须在编译时处理,否则会编译失败。通常有两种处理异常的方法:使用“try/catch”来捕获异常使用“throws”来声明异常。下面就来详细说说吧!上面已经提到了异常处理,通常有两种处理异常的方法。我们先来看看捕获异常。捕获异常是通过三个关键字实现的:try-catch-finally。使用try来执行程序。如果发生异常,系统抛出异常,可以通过其类型进行捕获(catch)和处理。最后一步是通过finally语句为异常处理提供一个统一的出口。最后指定的代码必须被执行。这个捕获异常其实是我们在面试的时候经常遇到的问题。接下来就为每个部分做一个简单的提醒吧!(1)try一个try语句必须至少有一个catch语句块或一个finally语句块。当异常处理代码执行结束时,不会返回到try语句去执行还没有执行完的代码。(2)catch每个try语句块都可以伴随一个或多个catch语句来处理可能产生的不同类型的异常对象。下面介绍一些常用的方法,继承自Throwable类。toString()方法显示异常的类名和异常的原因。getMessage()方法只显示异常原因,不显示类名。printStackTrace()方法用于在发生异常事件时跟踪堆栈的内容。这里有一个需要特别注意的地方,就是catch捕获异常时的捕获顺序:如果异常类之间存在继承关系,需要注意顺序排列。顶层的类应该放在底部,否则就省略多余的catch。也就是说,先捕获子类异常,再捕获父类异常。(3)finallyfinally语句块必须一直执行,除非遇到System.exit(0)结束程序执行。对于这个特性,我们通常会关闭finally中程序块已经打开的资源,比如:关闭文件流,释放数据库连接等。即使try和catch块中有return语句,finally语句也会执行.就是执行finally语句后通过return退出。这是一道非常经典的面试题。publicclassTest{publicstaticvoidmain(String[]args){System.out.println(newTest().test());;}staticinttest(){intx=1;try{retunx;}finally{System.out.print("jdbk"+++x);}}}//求输出结果?先解说这里的玄机!看了上面的描述,我们都知道try和catch中有return的时候,finally还是会被执行,所以这道题的答案按照正常逻辑应该是“jdbk22”,但是这里有个陷阱,就是is:finally在return之后的表达式操作之后执行(此时不返回操作后的值,而是先保存要返回的值,不管finally中的代码,返回值都不会改变,它仍然是之前保存的值),所以函数返回值是在最终执行之前确定的。所以正确答案应该是:“jdbk21”。另外需要注意的是:finally中最好不要包含return,否则程序会提前退出,而且返回值不是try或catch中保存的返回值。接下来说说声明异常,比较简单。在某些情况下,当前方法不需要处理发生的异常,而是向上传递给调用它的方法进行处理。如果一个方法抛出多个已检查的异常,则所有异常都必须列在方法的开头,以逗号分隔。publicstaticvoidreadFile(StringfileName)throwsFileNotFoundException,IOException{}需要注意:方法重写中声明异常时:子类重写父类方法时,如果父类方法有声明的异常,则声明的异常范围子类不能超出父类声明的范围。我们一般在server层声明异常。在控制器层或者数据访问层,一般都会捕获异常。自定义异常为什么我们需要自定义异常?不是因为在程序中,JDK提供的任何一个标准的异常类都未必能够完整描述我们想要表达的问题。此时我们可以创建自己的异常类,即自定义异常类。那么我们如何自定义异常类呢?相信看了上面异常类的家族图你应该猜到了。是的,自定义异常类只需要从Exception类或其子类中派生出一个子类即可。如果继承Exception类,则为checkedexception,必须处理;如果不想处理,可以让自定义异常类继承运行时异常RuntimeException类。通常我们的自定义异常类应该包含2个构造函数:一个是默认构造函数,一个是带有详细信息的构造函数。这是一个例子。/**IllegalAgeException:IllegalAgeException:IllegalAgeException,继承自Exception类*/classIllegalAgeExceptionextendsException{//默认构造函数publicIllegalAgeException(){}//带有详细信息的构造函数,信息保存在消息中publicIllegalAgeException(Stringmessage){super(message);}}publicvoidsetAge(intage)throwsIllegalAgeException{if(age<0){thrownewIllegalAgeException("一个人的年龄不应该是负数");}this.age=age;}最后给大家一些使用建议异常机制:避免使用异常处理代替错误处理,降低了程序的清晰度,效率低下。处理异常并不能代替简单的测试——仅在异常情况下使用异常机制。不要进行小粒度的异常处理——将整个任务包装在一个try块中。异常往往在高层处理。本文经授权转载自公众号“良墟Linux”。世界500强外企Linux开发工程师梁旭,在公众号分享大量Linux干货,欢迎关注!