JAVA异常与异常处理详解
一、异常简介
什么是异常?
异常就是有异于常态,和正常情况不一样,有错误出错。在java中,阻止当前方法或作用域的情况,称之为异常。
java中异常的体系是怎么样的呢?
1.Java中的所有不正常类都继承于Throwable类。Throwable主要包括两个大类,一个是Error类,另一个是Exception类;
2.其中Error类中包括虚拟机错误和线程死锁,一旦Error出现了,程序就彻底的挂了,被称为程序终结者;
3.Exception类,也就是通常所说的“异常”。主要指编码、环境、用户操作输入出现问题,Exception主要包括两大类,非检查异常(RuntimeException)和检查异常(其他的一些异常)
4.RuntimeException异常主要包括以下四种异常(其实还有很多其他异常,这里不一一列出):空指针异常、数组下标越界异常、类型转换异常、算术异常。RuntimeException异常会由java虚拟机自动抛出并自动捕获(就算我们没写异常捕获语句运行时也会抛出错误!!),此类异常的出现绝大数情况是代码本身有问题应该从逻辑上去解决并改进代码。
5.检查异常,引起该异常的原因多种多样,比如说文件不存在、或者是连接错误等等。跟它的“兄弟”RuntimeException运行异常不同,该异常我们必须手动在代码里添加捕获语句来处理该异常,这也是我们学习java异常语句中主要处理的异常对象。
二、try-catch-finally语句
(1)try块:负责捕获异常,一旦try中发现异常,程序的控制权将被移交给catch块中的异常处理程序。
【try语句块不可以独立存在,必须与 catch 或者 finally 块同存】
(2)catch块:如何处理?比如发出警告:提示、检查配置、网络连接,记录错误等。执行完catch块之后程序跳出catch块,继续执行后面的代码。
【编写catch块的注意事项:多个catch块处理的异常类,要按照先catch子类后catch父类的处理方式,因为会【就近处理】异常(由上自下)。】
(3)finally:最终执行的代码,用于关闭和释放资源(数据库连接,IO资源、网络连接socket等)。
==============================================================
语法格式如下:
try{ //一些会抛出的异常 }catch(Exception e){ //第一个catch //处理该异常的代码块 }catch(Exception e){ //第二个catch,可以有多个catch //处理该异常的代码块 }finally{ //最终要执行的代码 }
当异常出现时,程序将终止执行,交由异常处理程序(抛出提醒或记录日志等),异常代码块外代码正常执行。 try会抛出很多种类型的异常,由多个catch块捕获多钟错误。
多重异常处理代码块顺序问题:先子类再父类(顺序不对编译器会提醒错误),finally语句块处理最终将要执行的代码。
总结:
1、不管有没有出现异常或者try和catch中有return,finally块中代码都会执行;
2、finally中最好不要包含return,否则程序会提前退出,返回会覆盖try或catch中保存的返回值。
3. e.printStackTrace()可以输出异常信息。(Throwable的方法,异常信息:异常的原因、内容、位置。异常被封装成对象)
三、throw和throws关键字
java中的异常抛出使用throw和throws关键字来实现。
1、throw ----将产生的异常抛出,是抛出异常的一个动作。
一般会用于程序出现某种逻辑时程序员主动抛出某种特定类型的异常。
语法:throw (异常对象),如:
1 public static void main(String[] args) throws 异常类型 { 2 String s = "abc"; 3 if(s.equals("abc")) { 4 throw new NumberFormatException(); 5 } else { 6 System.out.println(s); 7 } 9 }
语法格式:
public void 方法名(参数列表) throws 异常列表 { // 抛出多个异常时,用逗号隔开 //调用会抛出异常的方法或者: throw new Exception();
}
当某个方法用于throws 声明,需要抛给调用者处理。如果调用者不处理就继续往上抛。都不处理最终抛到JVM,运行后在屏幕上(展现层)显示异常信息。
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
使用throw和throws关键字需要注意以下几点:
1.throws的异常列表可以是抛出一条异常,也可以是抛出多条异常,每个类型的异常中间用逗号隔开。
2.如果某个方法调用了抛出异常的方法,那么必须添加try catch语句去尝试捕获这种异常; 或者throws声明,将异常抛出给更上一层的调用者进行处理。
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
四、自定义异常
运行时异常(RuntimeException)以及其子类都无需进行throws声明。异常在继承或者实现中的使用细节:
1、子类重写父类方法时,如果父类的方法声明异常,子类只能声明父类异常或者该异常的子类,或者不声明。
2、当父类方法声明多个异常时,子类覆盖时只能声明多个异常的子集。
3、当被覆盖的方法没有异常声明时,子类覆盖时是无法声明异常的。
举例:父类存在这种情况,接口也有这种情况。
问题:接口中没有声明异常,而实现的子类覆盖方法时发生了异常,怎么办?
无法进行throws声明,只能catch捕获。万一问题处理不了呢?catch中继续throw抛出,但是只能将异常转换成RuntimeException子类抛出。
五、异常转换
异常转义就是将一种类型的异常转成另一种类型的异常,然后再抛出异常。
实现异常转换:异常通过try/catch捕获[做临时处理],再throw抛给调用者。throw抛出时,可以抛其他类型的异常。
建议
异常需要封装和传递,我们在进行系统开发的时候,不要“吞噬”异常,也不要“赤裸裸”的抛出异常,封装后在抛出,或者通过异常转义,可以达到系统更健壮、友好的目的。
六、结束语
java的异常处理的知识点杂而且理解起来也有点困难,我在这里给大家总结了以下几点使用java异常处理的时候,良好的编码习惯:
1、处理运行时异常时,采用逻辑去合理规避同时辅助try-catch处理
2、在多重catch块后面,可以加一个catch(Exception)来处理可能会被遗漏的异常
3、对于不确定的代码,也可以加上try-catch,处理潜在的异常
4、尽量去处理异常,切记只是简单的调用printStackTrace()去打印
5、具体如何处理异常,要根据不同的业务需求和异常类型去决定
6、尽量添加finally语句块去释放占用的资源
参考:
https://www.cnblogs.com/hysum/p/7112011.html#_label0。
毕向东。