------- android培训、java培训、期待与您交流! ----------
异常
异常:就是不正常,是指程序在运行时出现的不正常情况。其实就是程序中出现的问题。这个问题按照面向对象思想进行描述,并封装成了对象。
因为问题的产生有产生的原因、有问题的名称、有问题的描述等多个属性信息存在。当出现多属性信息最方便的方式就是将这些信息进行封装。
异常就是java按照面向对象的思想将问题进行对象封装。这样就方便于操作问题以及处理问题。
问题很多,意味着描述的类也很多,将其共性进行向上抽取,形成了异常体系。
异常的好处:
(1)将问题进行封装。
(2)将正常流程代码和问题处理代码相分离,方便于阅读。
异常体系的特点:
子类的后缀名都是用父类名作为后缀,阅读性很强。最终问题(不正常情况)就分成了两大类:
Throwable:
无论是Error,还是Exception。
问题,问题发生就应该可以抛出,让调用者知道并处理。
该体系的特点就在于Throwable及其所有的子类都具有可抛性。
可抛性到底指的是什么呢?throws throw
怎么体现可抛性呢?凡是可以被这两个关键字所操作的类和对象都具备可抛性。
1.一般不可处理的:Error
特点:是Jvm抛出的严重性的问题。
通常出现重大问题如:运行的类不在在或者内存溢出等。
这种问题发生一般不针对性处理。直接修改程序。
错误:通常是不编写代码对其进行针对处理。
2.可以处理的:Exception
处理Exception异常有两种方法:
一是:在运行时运行出现的一些情况,可以通过 try catch finally
二是:通过throws在函数上声明。(如果函数内throw异常,那么函数就必须声明)
处理异常(Exception)的几种格式:
格式一:
try{
可能发生异常的代码;
}
catch(捕获异常类的对象 异常类引用变量){
处理代码;
}
格式二:
try{
可能发生异常的代码;
}fianlly{一定要执行的语句;(通常用于关闭资源)
}
格式三:
try{
可能发生异常的代码;
}
catch(捕获异常类的对象 异常类引用变量){
处理代码;
}
finally{
一定要执行的语句;(通常用于关闭资源)
}
异常示例:
<span style="color:#000000;">class Test { public static void main(String[] args) { int[] arr = {1,3,5,7,9}; try{ System.out.println(arr[5]); } catch (Exception e){ System.out.println("数组角标越界"); } finally{ System.out.println("return 之前必须执行"); return ; } } } </span>
throw和throws的用法
(1) throw定义在函数内,用于抛出具体的异常对象,后面只能跟一个异常对象;
(2) throws定义在函数上,用于抛出异常类,可以抛出多个异常类,用逗号隔开;
声明异常(throws)
在可能出现异常的方法上声明抛出可能出现异常的类型;
声明的时候尽可能声明具体的异常,方便更好的处理.
当前方法不知道如何处理这种异常,可将该异常交给上一级调用者来处理(非RuntimeException类型的异常)。
方法一旦使用throws声明抛出方法内可能出现的异常类型,该方法就可以不再过问该异常了;
一个方法调用另一个使用throws声明抛出的方法,自己要么try...catch,要么也throws;
格式:
public 返回值类型 方法名(参数列表...)
throws异常类A,异常类B... {
}
throw
自行抛出一个异常对象,抛出异常类的对象;
若throw抛出的是Runtime异常:
程序可以显示使用try...catch来捕获并处理,也可以不管,直接交给方法调用者处理;
若throw抛出Checked异常:
要么放在try里自己处理,要么放在一个throws声明的方法里面,交给调用者处理。
格式:
public static void main(String[] args) {
try {
fn1(1);
} catch (Exception e) {e.printStackTrace(); }
fn2(2);
}
publicstatic void fn1(int a) throws Exception{
if(a >0) { throw newException("fn1 -- a值不合法"); }
}
publicstatic void fn2(int a) {
if(a >0) { throw newRuntimeException("fn2 -- a值不合法"); }
}
异常处理的原则:
1.函数内容如果抛出需要检测的异常,那么函数上必须要声明。
否则必须在函数内用try catch捕捉,否则编译失败。
2.如果调用到了声明异常的函数,要么try catch要么throws,否则编译失败。
(如果调用的函数抛出异常,那么调用者可以try catch也可以throws)
(如果调用的是覆写父类的函数抛出异常,那么调用者只能抛出父类同样的异常,或者父类异常的子集)
3.什么时候catch,什么时候throws 呢?
功能内容可以解决,用catch。
解决不了,用throws把异常告诉调用者,由调用者解决 。
4.一个功能如果抛出了多个异常,那么调用时,必须有对应多个catch进行针对性的处理。
内部有几个需要检测的异常,就抛几个异常,抛出几个,就对应有几个catch。
5.抛到最后抛给谁才是个头呢?答案是抛到虚拟机才是头。
fianlly 特殊之处:
finally语句中定义的是一定要执行的语句,通常用于关闭资源。(因为资源必须释放)
finally除非遇到System.exit(0);也是就虚拟机退出才不会执行。
子类覆盖父类时对异常处理的注意事项:
1、如果父类的方法抛出异常,那么子类的覆盖方法,只能抛出父类的异常或者该异常的子类。
2、如果父类方法抛出多个异常,那么子类再覆盖该方法时,只能抛出父类异常的子集。
(也就是父类如果抛多个异常,那么我们不能直接抛Exception异常。)
(如果抛一个异常的时候,是可以抛父类异常的)
3、如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常。
4、如果子类方法发生了异常,就必须要进行try处理,绝对不能抛。
5、如果在子类的覆盖方法确实需要抛出非父类的异常或者该异常的子类,则必须在内部解决。
自定义异常
定义类继承Exception或者RuntimeException
(其实我们这样也是用面向对象思考问题,把我们程序设计中可能出现的问题进行了封装。)
(1) 为了让该自定义类具备可抛性
(2) 让该类具备操作异常的共性方法
(3) 当要自定义异常的信息时,可以使用父类已经定义好的功能,异常信息传递给父类的构造函数。
<span style="color:#000000;">import Java.util.Random; class MyException extends Exception{ MyException(String message){ super(message);//父类带参数的构造函数 } } /* 在我们的程序中,数组为空就会发生空指针异常。 */ class Test { public static void main(String[] args) /*throws Exception ...当然这里也可以直接把问题抛出去*/{ //定义了一个空数组 int[] arr =new int[0]; try{ /* 对调用的方法进行try catch处理。 */ method(arr); } catch(Exception e){ /* 跟踪打印下抛异常的类和问题 */ System.out.println(e.toString());//MyException: 空指针异常 } } /* 定义一个方法,打印一下数组,对数组进行空指针判断,如果为空发生异常 */ public static void method(int[] arr)throws Exception{ if(arr.length==0) /* 如果数组为空,就在函数内抛出异常,在函数上声明抛出的异常。 */ throw new MyException("空指针异常"); } System.out.print("["); for(int x=0;x<arr.length;x++){ System.out.print(arr[x]); } System.out.println("]"); } //注意:当捕获到的异常,本功能处理不了时,可以继续在catch中抛出,让调用者去处理。 public static void method(){ try{ 异常代码; } catch(MyException e){ throw new MyException("MyException"); } } </span>
常见异常:
1.脚标越界异常(IndexOutOfBoundsException)包括数组、字符串;
2.空指针异常(NullPointerException)3.类型转换异常:ClassCastException
4.没有这个元素异常:NullPointerException