------
Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
内容提要:
异常概述
异常体系
异常类型
异常处理
throws和throw的区别
调用者对抛出异常的处理
RuntimeException
异常处理方式和原则
多异常处理
自定义异常
继承中的异常处理
异常练习
异常体系
异常类型
异常处理
throws和throw的区别
调用者对抛出异常的处理
RuntimeException
异常处理方式和原则
多异常处理
自定义异常
继承中的异常处理
异常练习
异常是Java中的重要机制,使用了面向对象的思想进行封装。
异常,简而言之就是程序中可能出现的错误或者问题。就像人会生病,不一定经常有,但总有生病的时候,而生病的原因各有不同,性质不一样,对其的治疗手法自然不同。
异常概述
对于计算机程序而言,情况更复杂,没有人能保证自己写的程序永远不会错,就算程序没有错误,能保证用户总是按你的意愿来输入?能保证运行该程序的操作系统永远稳定?能保证运行该程序的硬件不会突然坏掉?能保证网络永远通畅?
Java在设计异常体系时,将容易出现的情况都封装成了对象。
异常就是程序在运行时出现的不正常情况。
异常的由来:问题也是现实生活中一个具体的事物,也可以java的类的形式进行描述,并封装成对象;其实异常就是Java对不正常情况进行描述后的对象体现。体现在于:
“一个问题产生后,既有问题的原因,又有问题的现象,还有一些其他的问题信息,这些内容都可用封装的类进行体现并提取。”
对于问题的划分:两种,一种是严重的问题,另一种是非严重问题。对于严重的,java通过Error类进行描述,对于Error一般不编写针对性的代码对其进行处理(是JVM搞不定的部分);对于非严重问题,Java通过Exception类进行描述。而Exception可以使用针对性的处理方式进行处理(JVM能够搞定的部分,也是JVM能够识别的部分,JVM处理结果:JVM立刻停止运行)。
无论Error或者Exception都具有一些共性内容,比如不正常情况的信息、引发原因等。
异常的好处:将问题进行封装;将正常流程代码和问题处理代码相隔离,方便于阅读。
异常体系
此时将两者共性向上抽取形成了Throwable类,如下是Java的异常体系:
Throwable
|—— Error 通常出现重大问题,如运行的类不存在或者内存溢出等。
|—— Exception 运行时出现的一些情况
|—— RuntimeException 特殊异常类,抛出时不需要声明
Error和Exception的子类名都是以父类名作为后缀。
异常体系的特点:
其一、异常体系中的所有类以及建立的对象都具备可抛性;
其二、异常体系中的建立的对象可以被throw和throws关键字操作;
其三、只有异常体系具备这个特点。(什么意思?这里的异常指的是Exception吗?)
异常类型
异常有两种:
其一:编译时被检查异常。
该异常在编译时,如果没有处理(没有抛出也没有被try),则编译失败;该异常被标识,代表着可以被处理。详细地说明:在JAVAC编译时期,会去检测,如果方法中抛出了非RuntimeException 或者其子类,在方法中没有标示抛出异常,就视为有安全隐患的,表示这个异常是可以被处理的,并让调用者做出处理动作,在标示出异常的同时,调用者也必须有对应的处理方式,要么继续抛异常,要么try;
其二:运行时异常(编译时不检查)。
在编译时,不需要处理,编译器不检查。该异常的发生,建议不处理,并让程序停止,以此让程序员对代码进行修正。如RuntimeException以及其子类。凡是RuntimeException或者其子类会做一个判断instanceof RuntimeException,假若是true,则不管,目的在于让程序停止。
异常处理
Java内部的新建文件操作,是基于系统资源调用,即借用了Windows或者Linux的系统操作实现。
Java内部的新建文件操作,是基于系统资源调用,即借用了Windows或者Linux的系统操作实现。
Java提供了特有的语句进行异常处理,try…catch(异常类 变量)…finally…,以上由三个部分组成。
Try…catch…finall…的其他调用格式:第一种,try…catch…;第二种:try…catch…finally…;第三种:try…finally…;第四种:try…catch…catch…等。注意:catch是用于处理异常的,如果没有catch语句块,就代表异常没有被处理过,如果该异常是检测时异常,那必须声明。
其中try部分写需要被检测的代码,catch部分写处理异常的代码,也就是处理方式,finally是一定会执行的语句。
异常处理的流程:try块里面写需要检测的代码块,如果不写这部分,一旦出现了异常会直接将异常抛给JVM,JVM会启动虚拟机的默认异常处理机制,并导致程序中断。而try块就是为了防止将异常抛给JVM,而将异常抛给catch代码块处理。
异常处理的流程:try块里面写需要检测的代码块,如果不写这部分,一旦出现了异常会直接将异常抛给JVM,JVM会启动虚拟机的默认异常处理机制,并导致程序中断。而try块就是为了防止将异常抛给JVM,而将异常抛给catch代码块处理。
需要注意的是:
1.finally语句块(数据库主机服务器(CPU资源限制)的连接数也是有限的,)中的内容是一定会执行的部分,通常用于关闭资源(或者一定要执行的代码),否则增加运行压力。
1.finally语句块(数据库主机服务器(CPU资源限制)的连接数也是有限的,)中的内容是一定会执行的部分,通常用于关闭资源(或者一定要执行的代码),否则增加运行压力。
2.finally语句只有一种情况不会执行,当执行到System.exit(0)时,finally语句将不被执行。
对捕获到的异常进行常见方法操作:e.getMessage():输出异常;e.toString():异常名称:异常信息;e.printStackTrace():异常名称,异常信息以及出现的位置。
对捕获到的异常进行常见方法操作:e.getMessage():输出异常;e.toString():异常名称:异常信息;e.printStackTrace():异常名称,异常信息以及出现的位置。
JVM默认的异常处理机制就是调用printStackTrace,以此打印异常的堆栈跟踪信息。
一旦try部分出现异常,出现异常的代码之后的部分将不执行。
public class ExceptionDemo { public static void main(String[] args) { // TODO Auto-generated method stub Demo d = new Demo(); try { int x = d.div(4, 0); System.out.println("x = " + x); } catch (Exception e) { // Exception e = new ArithmeticException(); System.out.println("除零了"); } System.out.println("over"); } } class Demo { int div(int a, int b) { return a / b; } }
代码分析:异常的处理,在try语句块中写入需要“被检测”的代码,若通过,则不执行catch语句块中的代码,若抛出异常,则执行catch语句块,并在结束后执行catch语句块之后的代码。但是需要指出的是:一旦参数传入有误,而引起了异常(下一步执行catch语句时),将导致程序停止。这种方式是“不友好”的方式。
在功能上通过throws关键字声明该功能有可能出现异常,“未报告的异常错误,必须对其进行捕获或声明以便抛出!”对抛出的异常进行处理,否则编译失败。
public class ExceptionDemo2 { public static void main(String[] args) { // TODO Auto-generated method stub Demo2 d = new Demo2(); int x = d.div(4, 1); //有可能发生问题!!因为已经throws Exception //假如不处理,则编译不能通过 System.out.println("x = " + x); System.out.println("over"); } } class Demo2 { int div(int a, int b) throws Exception{ //在功能上通过throws声明该功能有可能会出现问题 return a / b; } }代码分析:throws的作用是告诉该方法的调用者:这个方法有可能引发异常,希望得到调用者的注意。如果调用者对这个问题“毫不在意”,编译器将直接发出错误信息,导致编译无法通过。有两种方式:捕获或声明以便抛出,进行处理该问题。
public class ExceptionDemo2 { public static void main(String[] args) throws Exception{ // TODO Auto-generated method stub Demo2 d = new Demo2(); int x = d.div(4, 1); //有可能发生问题!!因为已经throws Exception //假如不处理,则编译不能通过 System.out.println("x = " + x); System.out.println("over"); } } class Demo2 { int div(int a, int b) throws Exception{ //在功能上通过throws声明该功能有可能会出现问题 return a / b; } }代码分析:将异常抛出给JVM,由JVM代为处理。
public class ExceptionDemo2 { public static void main(String[] args){ // TODO Auto-generated method stub Demo2 d = new Demo2(); try{ int x = d.div(4, 0); //有可能发生问题!!因为已经throws Exception //假如不处理,则编译不能通过 System.out.println("x = " + x); } catch(Exception e) { System.out.println("有问题了!"); System.out.println(e.toString()); //异常处理方式有很多 } System.out.println("over"); } } class Demo2 { int div(int a, int b) throws Exception{ //在功能上通过throws声明该功能有可能会出现问题 return a / b; } }代码分析:这种方式并不是向JVM抛出异常,而是自己处理这个异常。
throws和throw的区别
throws使用在函数上,用于抛出异常类,可以抛出多个异常,并用逗号隔开。
throws使用在函数上,用于抛出异常类,可以抛出多个异常,并用逗号隔开。
throw使用在函数内部,用于抛出异常对象。
throw单独存在时,下面不要定义语句,因为执行不到。
当函数内有throw抛出的异常对象,并未进行try处理,必须要在函数上进行声明,否则编译失败。
注意:RuntimeException除外,也就是说,函数内部要是抛出了RuntimeException异常,函数上可以不需要声明。
如果函数声明了异常,调用者需要进行处理,处理方法可以throws或者throw。
调用者对抛出异常的处理
当在函数内部出现了throw抛出异常对象,那么就必须要给对应的处理动作。要么在内部try...catch...处理,要么在函数上声明让调用者自行处理。
一般情况下,函数内出现异常,函数上需要声明。在功能上通过throws的关键字声明该功能可能会出现异常的类型。
RuntimeException
Exception中有一个特殊的子类异常RuntimeException运行时异常,
Exception中有一个特殊的子类异常RuntimeException运行时异常,
1)如果在函数内部抛出该异常,函数可以不用声明,编译一样通过;
2)如果在函数上声明了该异常,调用者可以不用进行处理,编译一样通过。
为什么?之所以不用在函数上声明,是因为不需要让调用者处理。当该异常发生时,希望程序停止,因为在运行时出现了无法继续运算的情况,希望停止程序后对代码进行修正。
异常处理方式和原则
异常处理方式和原则
如果函数声明了异常,调用者需要进行处理:try或者throws。
当捕获到的异常,本功能处理不了时,可以继续在catch中抛出。
如果该异常处理不了,但并不属于该功能出现的异常,可以将异常转换后,再抛出和该功能相关的异常。
当在函数内部出现了throw抛出异常对象,下一步就必须给出对应的处理动作,要么在内部进行try…catch…处理,要么在函数上声明(通过关键字throws声明,通知调用者:这个方法有可能产生异常)让调用者处理(要么try,要么抛出异常,并让其他人进行处理。)。
多异常处理
声明异常时,建议声明更为具体的异常,这样可以更加具体地对异常进行处理;
声明异常时,建议声明更为具体的异常,这样可以更加具体地对异常进行处理;
一般声明几个异常,就对应有几个catch块,不要定义多余的catch块,即有针对性的处理异常。
如果多个catch块中的异常出现继承关系,父类异常catch块放在最下面。
建议:在进行catch块处理时,catch中一定要定义具体处理方式,不要简单地书写一条输出语句。
硬盘文件:异常日志文件,记录着软件出现的bug,软件开发人员根据日志文件进行软件调试和除错。
public class ExceptionDemo3 { public static void main(String[] args){ // TODO Auto-generated method stub Demo3 d = new Demo3(); try{ int x = d.div(4, 1); System.out.println("x = " + x); } catch(ArithmeticException e) { System.out.println(e.toString()); System.out.println("除零了!"); } catch(ArrayIndexOutOfBoundsException e) { System.out.println(e.toString()); System.out.println("越界了!"); } catch(Exception e) { System.out.println(e.toString()); } System.out.println("over"); } } class Demo3 { int div(int a, int b) throws ArithmeticException, ArrayIndexOutOfBoundsException{ int[] arr = new int[a]; System.out.println(arr[4]); return a / b; } }代码分析:多异常的处理这对于不同的异常情况,有针对性的进行处理。
自定义异常
含义:“对本项目涉及到的异常进行自我封装”。 因为项目中会出现一些特有问题,而这些问题并未被Java所描述并封装对象,所以对于这些特有的问题可以按照Java的封装思想,将特有问题进行自定义异常封装。
含义:“对本项目涉及到的异常进行自我封装”。 因为项目中会出现一些特有问题,而这些问题并未被Java所描述并封装对象,所以对于这些特有的问题可以按照Java的封装思想,将特有问题进行自定义异常封装。
自定义的异常Java不认识,这个时候需要我们编写代码手动抛出异常(自动抛出异常由Java捕获)。
自定义异常必须让其具备两个属性:1.为了让该自定义类具备可抛性;2.让该类具备操作异常的共性方法。
在自定义异常时:分析该问题出现时能不能处理,如果不能处理,需要修正代码的时候,就继承RuntimeException;假若问题出现时,可以处理,处理完后程序还能继续运行,那就继承Exception。
要么继承RuntimeException,要么继承Exception。
发现打印的自定义异常中只有异常名称,却没有异常信息;因为自定义的异常并未定义信息。
如何定义异常信息呢?因为在父类中已经把异常信息的操作都实现了,所以子类只要在构造时,将异常信息传递给父类通过super语句调用,就可以直接通过getMessage()方法获取自定义的异常信息了。
为什么要继承Exception?异常体系有一个特点,因为异常类和异常对象(也就是Exception类和对象)都需要被抛出,他们都具备可抛性,这个可抛性是Throwable这个体系中独有特点,只有这个体系中的类和对象才可以被throws和throw操作。
public class ExceptionDemo4 { public static void main(String[] args) { // TODO Auto-generated method stub Negative n = new Negative(); try { int x = n.div(4, -1); 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"); } } class FuShuException extends Exception { // 自定义异常 private int value; FuShuException() { super(); } FuShuException(String msg, int value) { super(msg); this.value = value; } public int getValue() { return value; } } class Negative { int div(int a, int b) throws FuShuException { // 将抛出的异常,在调用者(方法)上进行抛出 if (b < 0) throw new FuShuException("出现了除数是负数的情况", b); // 手动通过throw关键字抛出自定义异常 return a / b; } }代码分析:自定义异常的定义以及应用。
继承中的异常处理
子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法,只能抛出父类的异常或该异常的子类,或者不抛出异常。
如果父类方法抛出多个异常,那么子类在覆盖该方法时,只能抛出父类异常的子集。
原则只有一个:子类抛出的异常必须是父类的异常的子集或者子类,父类能够处理的异常。
如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常。如果子类方法发生了异常就必须要进行try…catch…处理,绝对不能抛异常。
/* * 继承关系: * Exception * |--AException * |--BException * |--CException */ class AException extends Exception { } class BException extends Axception { } class CException extends Exception { } class Fu { void show() throws AException { //父类抛出AException异常 } } class Test { void function(Fu f) { try { f.show(); } catch (AException e) { } } } class Zi extends Fu{ void show() throws CException{ //父类抛出CException异常(和AException同级别),编译无法通过 //父类中的catch无法处理该异常 } }异常练习
/* * 老师使用电脑讲课 * 描述电脑: * 电脑运行; * 电脑重启; * 描述电脑的问题: * 电脑蓝屏; * 电脑起火; * * 描述老师: * 老师使用电脑; * 老师讲课; * 描述老师可能出现的问题: * 老师不能继续讲课,让学生做练习。*/ public class ExceptionTest { public static void main(String[] args) { // TODO Auto-generated method stub Teacher t = new Teacher("毕老师"); try { t.teach(); } catch (StopTeachException e) { System.out.println(e.toString()); System.out.println("换老师或放假"); } } } class Teacher { private String name; private Computer cpt; Teacher(String name) { this.name = name; cpt = new Computer(); } public void teach() throws StopTeachException { try { cpt.run(); } catch (BlueScreenException e) { System.out.println(e.getMessage()); cpt.reset(); } catch (FireBreakingException e) { test(); throw new StopTeachException("Teacher_stopTeach:" + e.getMessage()); } System.out.println(name + "Teacher_teaching"); } void test() { System.out.println("电脑坏了,学生做练习"); } } class Computer { int start = 3; void run() throws BlueScreenException, FireBreakingException { if (start == 2) throw new BlueScreenException("Computer_BlueScreen"); else if (start == 3) throw new FireBreakingException("Computer_FireBreaking"); System.out.println("Computer running"); } void reset() { start = 1; System.out.println("Computer_reset"); } } class BlueScreenException extends Exception { BlueScreenException(String msg) { super(msg); } } class FireBreakingException extends Exception { FireBreakingException(String msg) { super(msg); } } class StopTeachException extends Exception { StopTeachException(String msg) { super(msg); } }