Java异常详解
来源:互联网 发布:那些违规毁了的淘宝店 编辑:程序博客网 时间:2024/06/05 15:41
一、异常
1、异常的概述
1)异常:就是程序在运行时出现不正常情况。
2)异常由来:问题也是现实生活中一个具体的事物,也可以通过java类的形式进行描述。并封装成对象。其实就是java对不正常情况进行描述后的对象体现。
2、异常的体系
对于问题的划分有两种:一种是严重的问题,java通过Error类对其进行描述,对于Error一般不编写针对性代码进行处理;一种是非严重的问题,java通过Exception类对其进行描述,对于Exception可以使用针对性的处理方式进行处理。无论Error或者Exception都具有一些共性内容。比如:不正常情况的信息,引发原因等。将它们向上提取,可以得到Java中所以异常的父类Throwable。
Throwable
|–Error
|–Exception
|–RuntimeException//特殊异常类,抛时不需要声明
|–其他异常类
异常体系的特点:
1、异常体系中的所有类以及建立的对象都具备可抛性。
2、也就是说可以被throw和throws关键字所操作。
3、只有异常体系具备这个特点
3、异常的分类
unchecked Exception(未检查异常):任何Error的子类以及RuntimeException的子类都称为未检查异常,编译时不会报错。
checked Exception(已检查异常):其他的异常都被称为已检查异常。该异常如果没有被处理(没有抛也,没有try),编译时会报错。
所有运行时异常均继承自RuntimeException类,常见的有:
NullPointerException - 空指针引用异常 ClassCastException - 类型强制转换异常。 IllegalArgumentException - 传递非法参数异常。 ArithmeticException - 算术运算异常 ArrayStoreException - 向数组中存放与声明类型不兼容对象异常 IndexOutOfBoundsException - 下标越界异常 NegativeArraySizeException - 创建一个大小为负数的数组错误异常 NumberFormatException - 数字格式异常 SecurityException - 安全异常 UnsupportedOperationException - 不支持的操作异常
4、声明并抛出异常
Java中使用throws关键字用来声明异常,自己并不处理异常,而是将该异常传递给调用者,让调用者去处理这个异常。throw关键字用来抛出异常。throws用在方法头上,后面跟的是异常的类;throw用在方法体中,后面跟的是一个异常的对象。
1)声明异常
Java方法使用throws关键字在其方法头中声明可能抛出的异常。例如,Java中的BufferrdReader类中的readLine方法。
public String readLine() throws IOException
该方法头表明方法会返回一个字符串,同时也可能抛出一个IOException异常对象。如果一个方法要抛出多个异常,可以用逗号将它们分开。
public void method() throws IOException,MalformedURIException
什么时候需要在方法头中使用throws关键字呢?
a、调用了一个会抛出checked Exception的方法,如readLine方法。
b、程序运行中发生错误,并且用throw(不是throws)关键字抛出一个checked Exception。
注意:a、不需要声明Java的内部错误,也就是那些从Error类继承来的错误。
b、不应该声明从RuntimeException继承来的异常。
总之,一个方法必须声明它可能抛出的全部checked Exception,而unchecked Exception要么是不可控制的(Error),要么是开发人员应该避免的(RuntimeException)。如果方法没有声明所有checked Exception,则编译器会给出错误信息。
2)抛出异常
假设有一个ShenXian类,类中有一个shiFa方法。正常情况下,每个神仙都可以变法术,但法术也有偶尔失灵的情况(异常)。此时,可以有shiFa这个方法抛出一个Exception异常对象。
class ShenXian{ //连续五次施法则法术失灵 public void shiFa(int i) throws Exception{//使用throw关键字在shiFa这个方法头上声明异常 if(i == 5){ throw new Exception();//使用throw关键字抛出自定义异常对象。 } System.out.println("第"+i+"次施法成功"); } public static void main(String [] args) throws Exception{//使用throws关键字声明异常并将异常传给JVM ShenXian shenxian = new ShenXian();//建立一个ShenXian类的对象 for (int i = 1; i < 7;i++){ shenxian.shiFa(i); } }}
运行结果:
第1次施法成功第2次施法成功第3次施法成功第4次施法成功Exception in thread "main" java.lang.Exception at ShenXian.shiFa(ShenXian.java:5) at ShenXian.main(ShenXian.java:12)
shiFa这个方法头上用throws声明了可能发生的异常,并将该异常交给它的调用者去处理,它的调用者是主函数,也就是说让主函数去处理。但是主函数也用throws关键字声明了异常,并将该异常交给它的调用者去处理,它的调用者是JVM。也就是说,如果shiFa这个方法运行时发生了异常,它会用throw关键字抛出一个异常对象,这个对象最后会被传给虚拟机,交由虚拟机去处理。从打印出来的代码来看,前四次施法都成功了,打印出了代表施法成功的语句,当准备进行第5次时施法时,发现i == 5
这个条件满足,然后开始执行throw new Exception();
这条语句,抛出了一个异常对象,交给了主函数,主函数又将该异常对象交给了JVM,JVM调用默认处理异常的方法,在屏幕上打印出相关的异常信息。
5、处理异常
如果一个Java方法碰到异常,有两种处理方式:一是在方法内捕获(try-catch)这个异常,二是将异常声明(throws),由调用该方法的上级方法处理。对于第一种处理方式,一般采用try-catch-finally三段论的方式,代码格式如下:
try{ 需要被检测的代码;}catch(异常类 变量){ 处理异常的代码(处理方式)}finally{ 无论是否发生异常都会执行的代码 释放资源,如关闭I/O流,断开数据库连接。}
结合下面代码进行分析:
class Demo{ int div(int a,int b) throws ArithmeticException{ return a/b; }}class Test{ public static void main(String [] args){ Demo d = new Demo(); System.out.println("除法运算开始"); try{ int x = d.div(4,0); System.out.println("运算结果x="+x); } catch(Exception e){ System.out.println("Exception:除数不能为零"); } finally{ System.out.println("清理除法运算后的垃圾"); } }}
运行结果:
除法运算开始Exception:除数不能为零清理除法运算后的垃圾
Demo类中的div方法头中用throws声明了ArithmeticException异常,也就是说如果div方法运行时出现了异常,会将该异常交给它的调用者(主函数)去处理,主函数处理的方式就是使用try-catch-finally三段论方式。结合打印结果来分析,虚拟机执行完System.out.println("除法运算开始");
这条语句后,开始执行try代码块中的被检测语句,首先执行的是int x = d.div(4,0);
这条语句,因为要调用div方法,且div方法有throws声明了异常,所以div方法会抛出一个ArithmeticException异常对象给try代码块,try代码块会结合该异常对象来分析被检测代码是否属于这类异常,由于Java中的ArithmeticException异常类定义了除数不能为零,所以检测结果是int x = d.div(4,0);
这条语句确实属于ArithmeticException异常,这时候JVM就不在继续执行异常代码下面的代码了,也就是不执行System.out.println("运算结果x="+x);
这条语句了,并且会将由int x = d.div(4,0);
引起的异常交给相对应参数的catch代码块,然后JVM就会执行catch代码块中的处理该异常的方法。
处理语句的其他格式:
a、
try{}catch{}
b、
try{}finally{}
6、自定义异常类
虽然Java语言提供了许多异常种类,但是有些时候这些异常仍然不够用。例如,假设要设计一个给小学低年级学生使用的计算器,该计算器在执行减法运算时要保证减数不能大于被减数,如果发生了这种错误,则要抛出一个异常。但是Java异常体系中没有定义这样一个异常,此时就有必要建立一个自己的异常类。
建立一个自己的异常类很简单,步骤是新建一个类,并使该类继承Exception(一般都会选择直接继承Exception,或者继承RuntimeException以及它的子类这两种情况)。先来看下IOException源码是如何继承Exception的?
public class IOException extends Exception{ static final long serialVersionUID = 7818375828146090155L; public IOException(){ super(); } public IOException(String message){ super(message); } public IOException(String message,Throwable cause){ super(message,cause); } public IOException(Throwable cause){ super(cause); }}
类IOException直接继承了Exception,然后覆盖了Exception中的各个构造方法。我们可以参照它来建立我们自己的异常类。
public class BasicCalculator{ //减法运算 //使用throws关键字声明SubstractException异常,并将异常传给调用者处理。 public int substract(int i,int j) throws SubstractException{ if(i < j){ SubstractException e = new SubstractException(); throw e;//使用throw关键字抛出一个SubstractException异常对象。 } else{ return i-j; } } //加法运算 //使用throws关键字声明ArithmeticException异常,并将异常传给调用者处理。 public int add(int i,int j) throws NegativeException{ if(i < 0 || j < 0){ throw new ArithmeticException(); } return i+j; } //减法异常 class SubstractException extends ArithmeticException{ public SubstractException(){ super("减数大于被减数"); } } //负数异常 class NegativeException extends ArithmeticException{ public NegativeException(){ super("出现负数的异常"); } } public static void main(String [] args){ BasicCalculator cal = new BasicCalculator(); cal.add(2,5); cal.add(-2,-3); cal.substract(2,3); }}
运行结果:
Exception in thread "main" java.lang.ArithmeticException at BasicCalculator.add(BasicCalculator.java:17) at BasicCalculator.main(BasicCalculator.java:37)
从程序运行的结果看,其报错机制与Java语言自带的异常类没有什么不同。
7、异常的其他事项
1)异常的好处:
a、将问题进行封装。
b、将正常流程代码和问题处理代码相分离,方便于阅读
2)异常的处理原则:
a、处理方式有两种:try或者 throws。
b、调用到抛出异常的功能时,抛出几个,就处理几个。一个try对应多个catch。
c、多个catch时,父类的catch放到最下面。否则编译会报错,因为其余的catch语句执行不到。
d、catch内,需要定义针对性的处理方式。不要简单的定义printStackTrace,输出语句。也不要不写。当捕获到的异常,本功能处理不了时,可以继续在catch中抛出。例如,
try{ throw new AException();}catch (AException e){ throw e;}
如果该异常处理不了,但并不属于该功能出现的异常。可以将异常转换后,在抛出和该功能相关的异常。或者异常可以处理,当需要将异常产生后和本功能相关的问题提供出去,让调用者知道并处理。也可以将捕获异常处理后,转换新的异常。这样就好比在给别人转账时,如果ATM机出现故障,这时可以另外找地方去转,也可以告诉对方,转账不成功。
try{ throw new AException();}catch (AException e){ 对AException处理; throw new BException();}
2)异常的注意事项:
A、异常在子父类覆盖中的体现:
a,子类抛出的异常必须是父类的异常的子类或者子集。
b,如果父类或者接口没有异常抛出时,子类覆盖出现异常,只能try不能抛。
/*Exception |--AException |--BException |--CException*/class AException extends Exception{}class BException extends AException{}class CException extends Exception{}class Fu{ void show()throws AException{ }}class Test{ void function(Fu f){ try{ f.show(); } catch (AException e){ } }}class Zi extends Fu{ void show()throws CException{ //如果这里子类抛出CException,父类中的catch就无法处理, //这样就会导致编译失败,所以子类只能抛出父类中的异常或子集 }}
B、问题在内部被解决就不需要声明。
C、catch是用于处理异常。如果没有catch就代表异常没有被处理,如果该异常是checked Exception,那么必须声明。
- java异常处理详解
- java常见异常详解
- Java异常处理详解
- 【转载】Java异常详解
- Java异常详解
- java异常的详解
- java中的异常详解
- Java异常详解
- java中的异常详解
- java(22) - 异常详解
- java异常详解
- Java中异常详解
- java中异常详解
- JAVA 异常机制详解
- java异常详解
- Java中的异常详解
- java-异常详解
- java异常机制详解
- thinking In Java ---07 复用类
- 收集 ios 常用的工具
- 获取SQL Server连接数与监视SQL Server连接状态的方法
- SpringMVC Ajax请求
- Thinkphp上传文件,保存时显示乱码
- Java异常详解
- 第五周项目2 对象作为数据成员
- 图 深度优先遍历 广度优先遍历 非递归遍历 图解算法过程
- 【汇总】scanf、getchar、getch、getche、getc、fgetc、gets、fgets、getline
- 摄像机和镜头的基础知识
- 【web学习】如何绑定自己的Lofter独立域名——域名解析篇
- 堆和栈的区别
- PMBOK(第五版)学习笔记 —— 7 项目成本管理
- OC-点语法