黑马程序员-异常

来源:互联网 发布:javascript代码知乎 编辑:程序博客网 时间:2024/04/30 02:08

-----------android培训java培训、java学习型技术博客、期待与您交流! ------------


一、定义:

程序运行过程中的不正常现象就叫异常。(异常是什么?是对问题的描述。将问题进行对象的封装。)


二、异常的由来:

问题也是现实生活中一个具体的事物,也可以通过java的类的形式进行描述,并封装成对象。其实就是java对不正常情况进行描述后的对象体现。


三、异常的体系:


1、体系的由来:

导致程序运行不正常的现象有很多,所以,就有很多的异常对象。而这些异常对象存在着共性的内容。所以,可以不断的进行抽取。最终形成了异常的体系结构。


2、异常体系的根类是:Throwable


3、体系结构:

Throwable:
|--Error:重大的问题,表示编译时错误和系统错误,比如内存溢出等。我们处理不了,也不需要编写代码处理。
      |--Exception:一般性的错误,比如在java类库,用户方法以及运行时故障中都可能抛出Exception
,需要我们编写代码进行处理。
                |--RuntimeException:运行时异常,也叫“不受检查异常”。这种异常属于错误,我们不需要处理。

                         其实就是为了让他在运行时出问题,然后我们回来修改代码。

                         RuntimeException代表的是编程错误,如:

                    (1)无法预料的错误。比如从你控制范围之外传递进来的null引用,传递进来的除数为0等。

                    (2)程序员应该在代码中进行检查的错误。比如对于数组角标越界,就得注意一下数组的大小。


4、错误(error)和异常(Exception)的区别:

错误出现:不一定会中断程序,它会以另外错误的方式来运行程序。

异常出现:中断正在运行的程序


5、Throwable类的方法摘要:

getMessage():获取异常信息,返回字符串。
toString():获取异常类名和异常信息,返回字符串。
printStackTrace():获取异常类名和异常信息,以及异常出现在程序中的位置,输出至标准错误流。返回值void。


四、捕获异常:

 

1、try的由来:

如果在方法内部抛出了异常,这个方法将在抛出异常的过程中结束。要是不希望方法就此结束,可在方法内设置一个特殊的块来捕获异常。因为在这个块里“尝试”各种可能产生异常的方法调用,所以称为try块。

 

2、catch的由来:

抛出的异常必须在某处得到处理。这个“地点”就是异常处理程序。异常处理程序紧跟在try块之后,以关键字catch表示。

 

3、处理过程:

当异常被抛出时,异常处理机制将负责搜寻参数与异常类型相匹配的第一个处理程序,然后进入catch子句执行,此时认为异常得到了处理。一旦catch子句结束,则处理程序的查找过程结束。(注意与switch语句完全不同)


代码示例1:

class Demo// 异常处理{int div(int a, int b) throws Exception// 在功能上通过throws的关键字声明了该功能有可能会出现问题。{return a / b;}}class ExceptionDemo {public static void main(String[] args) {Demo d = new Demo();try {int x = d.div(4, 1);System.out.println("x=" + x);} catch (Exception e)// Exception e = new ArithmeticException();{System.out.println("除零啦");System.out.println(e.getMessage());// / by zero;System.out.println(e.toString());// 异常名称 : 异常信息。e.printStackTrace();// 异常名称,异常信息,异常出现的位置。// 其实jvm默认的异常处理机制,就是在调用printStackTrace方法。// 打印异常的堆栈的跟踪信息。}System.out.println("over");}}/*outputx=4over*/

代码示例2:

//对多异常的处理class Demo {int div(int a, int b) throws ArithmeticException,ArrayIndexOutOfBoundsException// 在功能上通过throws的关键字声明了该功能有可能会出现问题。{int[] arr = new int[a];System.out.println(arr[4]);return a / b;}}class ExceptionDemo2 {public static void main(String[] args) // throws Exception{Demo d = new Demo();try {int x = d.div(5, 0);// 如果是为报告的异常System.out.println("x=" + x);}catch (Exception e) {System.out.println("查看是什么异常:" + e.toString());}/* * 对两种异常进行处理。 catch (ArithmeticException e) { * System.out.println(e.toString()); System.out.println("被零除了!!"); *  * } catch (ArrayIndexOutOfBoundsException e) { * System.out.println(e.toString()); System.out.println("角标越界啦!!"); } */System.out.println("over");}}/*output:0查看是什么异常:java.lang.ArithmeticException: / by zeroover*/


五、自定义异常:

 

1、自定义时继承Exception或者RuntimeException的目的:


(1)为了让该自定义类具备可抛性。
    原因:异常体系有一个特点:因为异常类和异常对象都被抛出。即他们都具备可抛性。这个可抛性是Throwable这个体系中独有特点。也就是说,只有这个体系中的类和对象才可以被throws和throw操作。
(2)让该类具备操作异常的共性方法。

 

2、定义规则:

 

代码必须与异常说明保持一致。如果方法里的代码产生(throw抛出)了异常对象却没有进行处理,编译器会发现这个问题并提醒你:

(1)要么在内部try catch处理这个异常。
(2)要么在方法上声明此方法将产生异常(异常说明),让调用者处理。

否则编译失败。这种在编译时被强制检查的异常称为“被检查的异常”。

特例:RuntimeException不需要在方法上声明此方法将产生异常,它属于错误,将被自动捕获,被称为“不受检查异常”。

 

3、定义异常信息:

 

因为父类中已经把异常信息的操作都完成了,所以子类只要在构造时,通过super语句将异常信息传递给父类的构造函数,那么就可以直接通过getMessage方法获取自定义的异常信息。

 

4、自定义格式:

 

class MyExcepiton extends Exception
{
MyExcepiton(){}                  //没有异常信息的情况


MyExcepiton(String message)       //有异常信息的情况
{
super(message);
}
}


class MyException extends RuntimeException
{
MyExcepiton(){}                 //没有异常信息的情况


MyExcepiton(String message)       //有异常信息的情况
{
super(message);
}
}


5、代码示例:

class FuShuException extends Exception // getMessage();继承Exception自定义一个异常{private int value;FuShuException() {super();// 用父类方法}FuShuException(String msg, int value)// 用父类方法然后自定义一个方法{super(msg);this.value = value;}public int getValue()// 返回自定义方法的数值{return value;}}class Demo {int div(int a, int b) throws FuShuException {if (b < 0)throw new FuShuException("出现了除数是负数的情况------ / by fushu", b);// 手动通过throw关键字抛出一个自定义异常对象。return a / b;}}class ExceptionDemo3 {public static void main(String[] args) {Demo d = new Demo();try {int x = d.div(4, -9);System.out.println("x=" + x);} catch (FuShuException e) {System.out.println(e.toString());// System.out.println("除数出现负数了");System.out.println("错误的负数是:" + e.getValue());}System.out.println("over");}}/*output:FuShuException: 出现了除数是负数的情况------ / by fushu错误的负数是:-9over*/


六、throws和throw的区别


1、 throws可以单独使用,但throw不能


有throws的时候可以没有throw。
有throw的时候,如果throw抛的异常是Exception体系,必须有throws在方法上声明。


2、位置不同


throws用于方法的声明上,其后跟的是异常类名。
后面可以跟多个异常类,之间用逗号隔开。
throw用于方法体中,其后跟的是一个异常对象名。


3、由谁处理


throws语句用在方法声明后面,表示再抛出异常,由调用这个方法的上一级方法中的语句来处理
throw语句用在方法体内,表示抛出异常,由方法体内的语句处理 


4、抛出的东西不同


throws主要是声明这个方法会抛出这种类型的异常,使其他地方调用它时知道要捕获这个异常。
throw是具体向外抛异常的动作,所以它是抛出一个异常实例。


5、可能与事实


throws说明你有哪个可能,倾向 
throw的话,那就是你把那个倾向变成真实的了


七、Exception和RuntimeException的区别


1、Exception:一般性的错误,是需要我们编写代码进行处理的。
2、RuntimeException:运行时异常,这个我们也不需要处理。其实就是为了让他在运行时出问题,然后我们回来修改代码。
说明:
在用throws抛出一个的时候,如果这个异常是属于Exception的体系的时候,我们在调用的地方必须进行处理或者继续抛出。
在用throws抛出一个的时候,如果这个异常是属于RuntimeException的体系的时候,我们在调用的地方可以不用处理。(RuntimeException和RuntimeException的子类)


八、异常的分类


1、编译时被强制检测异常:


在编译时,若异常在函数内部解决(有catch),可以不用在函数声明后标识;
若该异常在函数中被抛出,但是没有被标识,系统认为其有安全隐患,编译失败;只有该异常被标识,代表这可以被处理。
若该异常被标识,但是没有被调用者处理(没有抛也没有try),编译也失败。   


2、编译时不被检测的异常(运行时异常,即:RuntimeException以及其子类)


在编译时,不需要处理,编译器不检查。
若该异常在运行时发生,建议不处理,让程序停止。需要对代码进行修正。


九、异常的处理语句

 

基本格式:try...catch...finally

try
{
     需要被检测的代码;(可能出现异常的代码)
}
catch(异常对象)
{
    处理异常代码
}
finally
{
    一定会执行的代码;(释放资源)
}



变形格式:

try...catch
try….finally
try...catch...catch...
try...catch...catch...finally
注意:catch是用于处理异常。如果没有catch就代表异常没有被处理过,如果该异常是检测时异常,那么必须在函数声明后标识。


十、异常在子父类覆盖中的规则:


1、子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法只能抛出父类的异常或者该异常的子类(或者不抛)。
2、如果父类方法抛出多个异常,那么子类在覆盖该方法时,只能抛出父类异常的子集。
3、如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常。如果子类方法确实发生了新异常,就必须要进行try处理。绝对不能抛。
总结:归根结底一句话,子类不能抛比父类多的异常
根源:早期的程序不能处理子类中出现的新异常


十一、异常的好处


1、将问题进行封装。
2、将正常流程代码和问题处理代码相分离,方便于阅读。


十二、异常的处理原则:


1、处理方式有两种:try 或者 throws。
2、调用到抛出异常的功能时,抛出几个,就处理几个。
一个try对应多个catch。
3、多个catch,父类的catch放到最下面。
4、catch内,需要定义针对性的处理方式;
不要简单的定义printStackTrace或输出语句,也不要不写;
 当捕获到的异常,本功能处理不了时,可以继续在catch中抛出。
try
{
throw new AException();
}
catch (AException e)
{
throw e;
}


如果该异常处理不了,但并不属于该功能出现的异常。
可以将异常转换后,再抛出和该功能相关的异常。


或者异常可以处理,当需要将异常产生后和本功能相关的问题提供出去,
让调用者知道并处理。也可以将捕获异常处理后,转换新的异常。
try
{
throw new AException();
}
catch (AException e)
{
// 对AException处理。
throw new BException();
}
比如,汇款的例子。
5、多个异常同时被捕获的时候,记住一个原则:先逮小的,再逮大的。
6、finally:永远被执行,除非退出jvm(当执行到System.exit(0);时,fianlly不会执行)。
7、finally中定义的通常是关闭资源代码。因为资源必须释放。


十三、面试题


1、final,finally,finalize区别。

 final是最终的意思。它可以用于修饰类,成员变量,成员方法。
  它修饰的类不能被继承,它修饰的变量是常量,它修饰的方法不能被重写。

 finally:是异常处理里面的关键字。
  它其中的代码永远被执行。特殊情况:在执行它之前jvm退出。System.exit(0);

 finalize:是Object类中的一个方法。
  它属于垃圾回收器调用的方式。



2、假如catch中有return语句,finally里中的代码会执行吗? 是在return前,还是在return后呢?


 答:会,在return前执行finally里面的代码。


十四、练习


示例代码1:

/* 编写一个类,在其main方法的try块里抛出一个Exception类的对象。传递一个字符串参数给Exception的构造器。在catch子句里捕获此异常对象,并且打印字符串参数。添加一个finally子句,打印一条信息以证明这里确实得到了执行 */class Exception1 extends Exception {Exception1(String msg) {super(msg);System.out.println("Exception1(String msg)");}}class Ex1 {public static void f() throws Exception1 {System.out.println("Throwing MyException from f()");Exception1 e = new Exception1("From f()");throw e;}public static void main(String[] args) {try {f();} catch (Exception e) {System.err.println("Caught Exception1");// 标准错误流,不会被重定向e.printStackTrace();} finally {System.out.println("Made it to finally");}}}/*output:Throwing MyException from f()Caught Exception1Exception1: From f()at Ex1.f(Ex1.java:14)at Ex1.main(Ex1.java:20)Exception1(String msg)Made it to finally*/
示例代码2:

/*使用extends关键字建立一个自定义异常类。为这个类写一个接受字符串参数的构造器,把此参数保存在对象内部的字符串引用中。写一个方法显示此字符串。写一个try-catch子句,对这个新异常进行测试。 */class Exception4 extends Exception {private String msg;Exception4(String msg) {super(msg);System.out.println("Exception4()");this.msg = msg;}protected void showS() {System.out.println("Message from Exception4: " + msg);}}public class Ex4 {public static void f() throws Exception4 {System.out.println("f()");throw new Exception4("Ouch from f()");}public static void main(String[] args) {try {f();} catch (Exception4 e) {System.err.println("Caught Exception4");e.printStackTrace();e.showS();}}}/*output:f()Caught Exception4Exception4()Exception4: Ouch from f()at Ex4.f(Ex4.java:21)at Ex4.main(Ex4.java:26)Message from Exception4: Ouch from f()*/


原创粉丝点击