Java基础知识之异常处理机制
2016-02-27 20:20
549 查看
一:异常概述 1.异常:就是程序在运行时出现的不正常情况.2 异常的由来:问题也是现实生活中的一个具体的事物,也可以通过Java的类的形式进行描述并封装成对象.其实就是Java对不正常的情况进行描述后的对象体现.
3.已经见过的异常:比如角标越界,空指针等都是。就对这些问题进行分类。而且这些问题都有共性内容比如:每一个问题都有名称,同时还有问题描述的信息,问题出现的位置,所以可以不断的向上抽取。形成了异常体系。二:异常体系对于问题的划分为两种:一种是严重的问题:Error,一种是非严重的问题Exception.Error:一般不编写正对性的代码对其进行处理;Exception:可以使用针对性的处理方式进行处理.异常的体系Throwable
|--Error严重问题,我们不处理,比如内存溢出。
|--Exception|--RuntimeException
运行期异常,肯定是我们的代码不够严谨,我们需要修正代码|--非RuntimeException 编译期异常,必须处理的,否则程序编译不通过举例:出国旅游
1.当你提着行李到机场发现,机场被炸掉了,严重的问题.2.飞机在出发前,发现没有油了,应该加油,出发前需要检查的问题;
3.飞机出发后,出现了强大气流,需要迫降,飞行过程中出现的问题;异常的处理:1.JVM的默认处理:如果程序没有定义异常的处理代码,JVM会有默认的处理方案:
把异常的名称,原因,位置等信息输出在控制台,但是程序不能继续执行了。2.自己处理:a:
Java提供了特有的语句进行处理:try{
需要被检测的代码;}catch(异常类 变量名){
处理异常的代码(处理方式);}
finall{一定会被执行的代码(释放资源);
}b:throws
把自己处理不了的,在方法上声明,告诉调用者,这里有问题
3.异常体系特点:
1.异常体系中的所有类以及建立的对象都具备可抛性.
2.也就是说可以被throw和throws关键字所操作.
3.只有异常体系具备这个特点.
4.Exception的子类名大都是以父类名作为后缀.
4.多个异常的处理:
a:每一个异常就写一个try...catch;麻烦代码看起来非常的杂乱.
b:写一个try,多个catch
try{
...
}catch(异常类名 变量名) {
...
}
catch(异常类名 变量名) {
...
}
...
注意:
1.出现的异常能尽量明确具体的异常类,用确切的具体异常类来处理.
2.出现多个异常的时候,异常出现了继承关系,父类异常应该放在最后面.
c:JDK7出现了一个新的异常处理方案:
try{
}catch(异常名1 | 异常名2 | ... 变量 ) {
...
}
注意:
A:处理方式是一致的。(实际开发中,很多时候可能就是针对同类型的问题,给出同一个处理)
B:多个异常间必须是平级关系。
建议:在进行catch处理的时候,catch中一定要定义具体的处理方式,不要简单的书写一条输出语句.
三.异常分类
1.编译时异常:Java程序必须显示处理,否则程序就会发生错误,无法通过编译
程序在运行中可能出现的问题,也可能不会出现问题,所以就需要对可能出现问题的代码进行一些处理,
如果程序在运行时出现了,就可以及时进行处理异常,不至于导致程序停止.
2.运行时异常:无需显示处理,也可以和编译时异常一样处理
RuntimeException(运行时异常):
是指因设计或实现方式不当而导致的问题.
说白了,就是程序员造成的,程序员小心谨慎是完全可以避免的异常.比如,
事先判断对象是否为null就可以避免NullPointerException异常,
事先检查除数不为0就可以避免ArithmeticException 异常;
特点:
这种异常Java编译器不会检查它,也就说程序中出现这类异常的时候,即使不处理也没有
问题,但是一旦出现异常,程序将异常终止,若采用异常处理,则会被相应的程序执行处理.
3.对于捕获到异常进行操作的常见方法
String getMessage():获取异常信息,返回字符串。
String toString():获取异常类名和异常信息,返回字符串。
返回此 throwable 的简短描述。结果是以下字符串的串联:
此对象的类的 name
": "(冒号和一个空格)
调用此对象 getLocalizedMessage() 方法的结果
如果 getLocalizedMessage 返回 null,则只返回类名称。
void printStackTrace():获取异常类名和异常信息,以及异常出现在程序中的位置。JVM的默认处理
void printStackTrace(PrintStream s):通常用该方法将异常内容保存在日志文件中,以便查阅。
4.声明异常:throws
有些时候,我们是可以对异常进行处理的,但是又有些时候,我们根本就没有权限去处理某个异常。
或者说,我处理不了,我就不处理了。
为了解决出错问题,Java针对这种情况,就提供了另一种处理方案:抛出。
格式:
throws 异常类名
注意:这个格式必须跟在方法的括号后面。
注意:
尽量不要在main方法上抛出异常。
因为调用main方法的是JVM,如果main方法抛出,发生异常时,就会由JVM默认处理.
小结:
编译期异常抛出,将来调用者必须处理。
运行期异常抛出,将来调用可以不用处理。
throw:在功能方法内部出现某种情况,程序不能继续运行,需要进行跳转时,就用throw把异常对象抛出。
在程序内部抛出一个异常对象,抛出异常类的对象;
若 throw 抛出的是 RuntimeException:
程序可以显示使用 try...catch 来捕获并处理,也可以不管,直接交给方法调用者处理;
若 throw 抛出编译时异常:
要么放在 try 里自己处理,要么放在一个 throws 声明的方法里面,交给调用者处理。
5.到底如何处理异常:
原则:如果该功能内部可以将问题处理,用try,如果处理不了,交由调用者处理,这是用throws
区别:
后续程序需要继续运行就try
后续程序不需要继续运行就throws
6.异常处理的变形格式:
try...catch...finally
try...catch...
try...catch...catch...
try...catch...catch...fianlly
try...finally
catch是用于处理异常的,如果没有catch语句就代表异常没有被处理过,如果该异常时编译时异常,必须要声明.
7.finally
finally用于释放资源,它的代码永远会执行。特殊情况:在执行到finally之前jvm退出了,
当执行到System.exit(0),fianlly不会执行。
四.自定义异常:
因为在实际开发中,会出现特有的异常,而这些问题并没有被Java所描述并封装成对象,
所以对于这些问题按照Java的封装思想,将特有问题进行自定义的异常封装.
而我们自己写的类是不能作为异常类来看,如果想要一个类是异常类,就必须要是异常体系中的一员.
两种方式:
继承Exception:如果是编译时的异常,就让自定义异常继承Exception;
继承RuntimeException:如果该异常的发生,无法再继续进行运算.让自定义异常继承RuntimeException;
继承异常体系的原因:
异常体系有一个特点,异常类和异常对象都被抛出,他们具备可抛性,这个可抛性是Throwable这个体系中的独有特点,
只有这个体系中的类和对象才可以被throw和throws操作.
如何自定义异常信息?
因为父类中已经把异常星系的操作都完成了,
所以子类只要在构造时,将异常星系传递给父类的,通过super语句,
就可以直接通过getMessage()方法获取自定义的异常信息.
继承自Exception或者RuntimeException,只需要提供无参构造和一个带参构造即可;
注意:
异常在子父类覆盖的体现
1.子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法只能抛出父类的异常或者该异常的子类.
2.如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法的时候,也不能抛出异常.
3.如果子类方法发生异常,就必须要进行try...catch处理,绝不能抛.
如果该异常处理不了,但并不属于该功能出现的异常。可以将异常转换后,再抛出和该功能相关的异常。
或者异常可以处理,当需要将异常产生后和本功能相关的问题提供出去,让调用者知道。并处理。
也可以将捕获异常处理后,转换新的异常。
五.异常好处
1、将问题进行封装.
2、将正常流程代码和问题处理代码相分离,方便于阅读.
六.面试题
1.throw和throws有什么区别?
throw:是使用在函数内,后面跟的是异常对象. 只能抛出一个异常对象
表示抛出异常,由该方法的内部的语句处理. throw则是抛出了异常,执行throw则一定抛出了某种异常
throws:是使用在函数方法声明上,跟的是异常类名. 可以声明多个异常类名.用逗号隔开.
表示抛出该异常,由该方法的调用者去处理.throws表示可能会有某些异常发生,但并不一定会发生.
2.编译期异常和运行期异常的区别?
编译期异常 必须要处理的,否则编译不通过
运行期异常 可以不处理,也可以处理
3.final,finally,finalize的区别?
final:是关键字,最终的意思,可以修饰类,成员变量,成员方法.
修饰类,类不能被继承;
修饰变量,变量是常量;
修饰方法,方法不能被重写;
finally:是异常处理的一部分,里面写的代码一定会被执行,用于释放资源,
特殊情况是在执行到finally的时候JVM退出了.
finalize:是Object类里面的方法,用于垃圾回收.
4.如果catch里面有return语句,请问finally里面的代码还会执行吗?如果会,请问是在return前,还是return后。
会执行,在return的前面。
准确的说,应该是在中间。
3.已经见过的异常:比如角标越界,空指针等都是。就对这些问题进行分类。而且这些问题都有共性内容比如:每一个问题都有名称,同时还有问题描述的信息,问题出现的位置,所以可以不断的向上抽取。形成了异常体系。二:异常体系对于问题的划分为两种:一种是严重的问题:Error,一种是非严重的问题Exception.Error:一般不编写正对性的代码对其进行处理;Exception:可以使用针对性的处理方式进行处理.异常的体系Throwable
|--Error严重问题,我们不处理,比如内存溢出。
|--Exception|--RuntimeException
运行期异常,肯定是我们的代码不够严谨,我们需要修正代码|--非RuntimeException 编译期异常,必须处理的,否则程序编译不通过举例:出国旅游
1.当你提着行李到机场发现,机场被炸掉了,严重的问题.2.飞机在出发前,发现没有油了,应该加油,出发前需要检查的问题;
3.飞机出发后,出现了强大气流,需要迫降,飞行过程中出现的问题;异常的处理:1.JVM的默认处理:如果程序没有定义异常的处理代码,JVM会有默认的处理方案:
把异常的名称,原因,位置等信息输出在控制台,但是程序不能继续执行了。2.自己处理:a:
Java提供了特有的语句进行处理:try{
需要被检测的代码;}catch(异常类 变量名){
处理异常的代码(处理方式);}
finall{一定会被执行的代码(释放资源);
}b:throws
把自己处理不了的,在方法上声明,告诉调用者,这里有问题
例如: public class ExceptionDemo { public static void main(String[] args) { } public static void method(){ int a = 10; // int b = 2; int b = 0; try { System.out.println(a / b); } catch (ArithmeticException e) { System.out.println("除数不能为0"); } finally{ System.out.println("一定会执行的代码"); } } }
3.异常体系特点:
1.异常体系中的所有类以及建立的对象都具备可抛性.
2.也就是说可以被throw和throws关键字所操作.
3.只有异常体系具备这个特点.
4.Exception的子类名大都是以父类名作为后缀.
4.多个异常的处理:
a:每一个异常就写一个try...catch;麻烦代码看起来非常的杂乱.
b:写一个try,多个catch
try{
...
}catch(异常类名 变量名) {
...
}
catch(异常类名 变量名) {
...
}
...
注意:
1.出现的异常能尽量明确具体的异常类,用确切的具体异常类来处理.
2.出现多个异常的时候,异常出现了继承关系,父类异常应该放在最后面.
c:JDK7出现了一个新的异常处理方案:
try{
}catch(异常名1 | 异常名2 | ... 变量 ) {
...
}
注意:
A:处理方式是一致的。(实际开发中,很多时候可能就是针对同类型的问题,给出同一个处理)
B:多个异常间必须是平级关系。
建议:在进行catch处理的时候,catch中一定要定义具体的处理方式,不要简单的书写一条输出语句.
三.异常分类
1.编译时异常:Java程序必须显示处理,否则程序就会发生错误,无法通过编译
程序在运行中可能出现的问题,也可能不会出现问题,所以就需要对可能出现问题的代码进行一些处理,
如果程序在运行时出现了,就可以及时进行处理异常,不至于导致程序停止.
2.运行时异常:无需显示处理,也可以和编译时异常一样处理
RuntimeException(运行时异常):
是指因设计或实现方式不当而导致的问题.
说白了,就是程序员造成的,程序员小心谨慎是完全可以避免的异常.比如,
事先判断对象是否为null就可以避免NullPointerException异常,
事先检查除数不为0就可以避免ArithmeticException 异常;
特点:
这种异常Java编译器不会检查它,也就说程序中出现这类异常的时候,即使不处理也没有
问题,但是一旦出现异常,程序将异常终止,若采用异常处理,则会被相应的程序执行处理.
代码: public static ExceptionDemo{ public static void main(String[] args) { int[] arr = { 1, 2, 3 }; //访问数组不存在的第三个角标,会出现数组角标越界异常. System.out.println(arr[3]); } } //程序会停止抛出ArrayIndexOutOfBoundsException。
3.对于捕获到异常进行操作的常见方法
String getMessage():获取异常信息,返回字符串。
String toString():获取异常类名和异常信息,返回字符串。
返回此 throwable 的简短描述。结果是以下字符串的串联:
此对象的类的 name
": "(冒号和一个空格)
调用此对象 getLocalizedMessage() 方法的结果
如果 getLocalizedMessage 返回 null,则只返回类名称。
void printStackTrace():获取异常类名和异常信息,以及异常出现在程序中的位置。JVM的默认处理
void printStackTrace(PrintStream s):通常用该方法将异常内容保存在日志文件中,以便查阅。
4.声明异常:throws
有些时候,我们是可以对异常进行处理的,但是又有些时候,我们根本就没有权限去处理某个异常。
或者说,我处理不了,我就不处理了。
为了解决出错问题,Java针对这种情况,就提供了另一种处理方案:抛出。
格式:
throws 异常类名
注意:这个格式必须跟在方法的括号后面。
注意:
尽量不要在main方法上抛出异常。
因为调用main方法的是JVM,如果main方法抛出,发生异常时,就会由JVM默认处理.
小结:
编译期异常抛出,将来调用者必须处理。
运行期异常抛出,将来调用可以不用处理。
throw:在功能方法内部出现某种情况,程序不能继续运行,需要进行跳转时,就用throw把异常对象抛出。
在程序内部抛出一个异常对象,抛出异常类的对象;
若 throw 抛出的是 RuntimeException:
程序可以显示使用 try...catch 来捕获并处理,也可以不管,直接交给方法调用者处理;
若 throw 抛出编译时异常:
要么放在 try 里自己处理,要么放在一个 throws 声明的方法里面,交给调用者处理。
例如: public class ExceptionDemo { public static void method2() { int a = 10; int b = 0; if (b == 0) { throw new ArithmeticException(); } else { System.out.println(a / b); } } public static void mehtod1() thorws ArithmeticException{ int a = 10; int b = 0; System.out.println(a/b); } }
5.到底如何处理异常:
原则:如果该功能内部可以将问题处理,用try,如果处理不了,交由调用者处理,这是用throws
区别:
后续程序需要继续运行就try
后续程序不需要继续运行就throws
6.异常处理的变形格式:
try...catch...finally
try...catch...
try...catch...catch...
try...catch...catch...fianlly
try...finally
catch是用于处理异常的,如果没有catch语句就代表异常没有被处理过,如果该异常时编译时异常,必须要声明.
7.finally
finally用于释放资源,它的代码永远会执行。特殊情况:在执行到finally之前jvm退出了,
当执行到System.exit(0),fianlly不会执行。
四.自定义异常:
因为在实际开发中,会出现特有的异常,而这些问题并没有被Java所描述并封装成对象,
所以对于这些问题按照Java的封装思想,将特有问题进行自定义的异常封装.
而我们自己写的类是不能作为异常类来看,如果想要一个类是异常类,就必须要是异常体系中的一员.
两种方式:
继承Exception:如果是编译时的异常,就让自定义异常继承Exception;
继承RuntimeException:如果该异常的发生,无法再继续进行运算.让自定义异常继承RuntimeException;
继承异常体系的原因:
异常体系有一个特点,异常类和异常对象都被抛出,他们具备可抛性,这个可抛性是Throwable这个体系中的独有特点,
只有这个体系中的类和对象才可以被throw和throws操作.
如何自定义异常信息?
因为父类中已经把异常星系的操作都完成了,
所以子类只要在构造时,将异常星系传递给父类的,通过super语句,
就可以直接通过getMessage()方法获取自定义的异常信息.
继承自Exception或者RuntimeException,只需要提供无参构造和一个带参构造即可;
注意:
异常在子父类覆盖的体现
1.子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法只能抛出父类的异常或者该异常的子类.
2.如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法的时候,也不能抛出异常.
3.如果子类方法发生异常,就必须要进行try...catch处理,绝不能抛.
如果该异常处理不了,但并不属于该功能出现的异常。可以将异常转换后,再抛出和该功能相关的异常。
或者异常可以处理,当需要将异常产生后和本功能相关的问题提供出去,让调用者知道。并处理。
也可以将捕获异常处理后,转换新的异常。
例如: public class MyException extends Exception { public MyException() { } public MyException(String message) { super(message); } }
五.异常好处
1、将问题进行封装.
2、将正常流程代码和问题处理代码相分离,方便于阅读.
异常练习: /* 毕老师用电脑上课。 开始思考上课中出现的问题。 比如问题是 电脑蓝屏。 电脑冒烟。 要对问题进行描述,封装成对象。 可是当冒烟发生后,出现讲课进度无法继续。 出现了讲师的问题:课时计划无法完成。 */ //自定义蓝屏异常 class LanPingException extends Exception { LanPingException(String message) { super(message); } } //自定义冒烟异常 class MaoYanException extends Exception { MaoYanException(String message) { super(message); } } //自定义无法上课异常。 class NoPlanException extends Exception { NoPlanException(String msg) { super(msg); } } //电脑类 class Computer { private int state = 1; public void run() throws LanPingException,MaoYanException { if(state==2) throw new LanPingException("蓝屏了"); if(state==3) throw new MaoYanException("冒烟了"); System.out.println("电脑运行"); } public void reset() { state = 1; System.out.println("电脑重启"); } } //老师类 class Teacher { private String name; private Computer cmpt; Teacher(String name) { this.name = name; cmpt = new Computer(); } public void prelect()throws NoPlanException { try { cmpt.run(); } catch (LanPingException e) { cmpt.reset(); } catch (MaoYanException e) { test(); throw new NoPlanException("课时无法继续"+e.getMessage()); } System.out.println("讲课"); } public void test() { System.out.println("练习"); } } class ExceptionTest { public static void main(String[] args) { Teacher t = new Teacher("毕老师"); try { t.prelect(); } catch (NoPlanException e) { System.out.println(e.toString()); System.out.println("换老师或者放假"); } } } /* 当电脑蓝屏的时候: 电脑重启,上课; 当电脑冒烟的时候: 学生做做练习 NoPlayException: 课时无法继续 原因是冒烟 换老师或者放假 */
六.面试题
1.throw和throws有什么区别?
throw:是使用在函数内,后面跟的是异常对象. 只能抛出一个异常对象
表示抛出异常,由该方法的内部的语句处理. throw则是抛出了异常,执行throw则一定抛出了某种异常
throws:是使用在函数方法声明上,跟的是异常类名. 可以声明多个异常类名.用逗号隔开.
表示抛出该异常,由该方法的调用者去处理.throws表示可能会有某些异常发生,但并不一定会发生.
2.编译期异常和运行期异常的区别?
编译期异常 必须要处理的,否则编译不通过
运行期异常 可以不处理,也可以处理
3.final,finally,finalize的区别?
final:是关键字,最终的意思,可以修饰类,成员变量,成员方法.
修饰类,类不能被继承;
修饰变量,变量是常量;
修饰方法,方法不能被重写;
finally:是异常处理的一部分,里面写的代码一定会被执行,用于释放资源,
特殊情况是在执行到finally的时候JVM退出了.
finalize:是Object类里面的方法,用于垃圾回收.
4.如果catch里面有return语句,请问finally里面的代码还会执行吗?如果会,请问是在return前,还是return后。
会执行,在return的前面。
准确的说,应该是在中间。
相关文章推荐
- 如何优雅地处理前端异常?
- C#异常处理详解
- 轻松学习C#的异常处理
- PHP异常处理Exception类
- JS异常处理的一个想法(sofish)
- PHP 的异常处理、错误的抛出及回调函数等面向对象的错误处理方法
- PHP如何抛出异常处理错误
- PHP中的错误处理、异常处理机制分析
- js中的异常处理try...catch使用介绍
- php5编程中的异常处理详细方法介绍
- php异常处理使用示例
- Asp.net Mvc 身份验证、异常处理、权限验证(拦截器)实现代码
- javascript 异常处理使用总结
- java多线程中的异常处理机制简析
- 深入理解Java编程中异常处理的优劣
- 分享一个php 的异常处理程序
- 简单了解Java编程中对异常处理的运用
- 深入剖析Java中的各种异常处理方式
- JS中的异常处理方法分享
- 一些.NET对多线程异常处理技巧分享