Java中异常的概念以及处理异常
在Java程序运行期间出现了一个错误,这个错误可能是由于文件包含了错误信息,或者是由于网络连接出现问题,也可以是因为使用了无效的数组下标,或者是试图使用一个没有被赋值的对象引用而造成的,我们称这样的错误为异常。在出现异常时用户期望程序能够采用一些理性的行为。如果由于出现错误而使得程序操作没有完成,这时程序应该:
从上图中我们可以知道,所有的异常类都是由Throwable继承下来的,但在下一层立即分为两个分支:Error和Exception。
一、Error
1、Error类层次描述了Java运行时系统的内部错误和资源耗尽错误。对于这类错误是无法难通过程序来解决的,所以程序不应该抛出这种类型的对象。如果出现了这样的内部错误,除了通知给用户,并尽力使程序安全地终止。当然这类情况是很少出现的
二、Exception
在设计Java程序时,Exception是我们需要重点关注的错误,在Java程序中Exception又可以分为两类:Runtime Exception、其它异常如:IOException。
1、派生于Runtime Exception 的异常主要包含以下几种情况
- 错误的类型转换
- 数组访问越界
- 访问空指针
2、不是派生于Runtime Exception的异常包含
- 试图在文件尾部读取数据
- 试图打开一个错误格式的URL
- 试图根据给定的字符串查找Class对象,而这个字符串表示的类并不存在
这里总结一条:如果是出现RuntimeException,那么就一定是自己的问题。
三、运行时异常和检查性异常
1、在Java语言中将派生于Error或RuntimeException类的所有异常称为运行时异常,这类异常我们可以不处理,当出现这个的异常时,总是由虚拟机接管,比如:我们从来没有人去处理过NullPointerException异常,它就是运行时异常,并且这种异常还是最常见的异常之一。运行时异常我们常见的有
ClassCastException(类转换异常)
、
IndexOutOfBoundsException(数组越界)
、
NullPointerException(空指针)
、
ArrayStoreException(数据存储异常,操作数组时类型不一致)
、
还有IO操作的BufferOverflowException异常
;
2、除了运行时异常,其它的异常都被称为
检查性异常
,
我们经常遇到的IO异常及sql异常就属于检查式异常。对于这种异常,Java编译器要求我们必须对出现的这些异常进行catch 所以 面对这种异常不管我们是否愿意,只能自己去写一堆catch来捕捉这些异常。常见的查检性异常有:FileNotFoundException 文件不存在异常、SQLException SQL异常等。
抛出和捕捉异常的方法
一、使用throws抛出异常
1、使用throws抛出异常的情况:
- 调用一个抛出已检查异常的方法,如:FileInputStream构造器
- 程序运行过程中发现错误,并且利用throw语句抛出一个已检查异常
- 程序出现错误,如:a[-1]=0会抛出一个ArrayIndexOutOfBoundsException这样的未检查异常
- Java虚拟机和运行时库出现的内部异常。
- public class A**Exception {
- private String id;
- public void setID(String id) throws IllegalException{
- if(id.length() == 7) {
- this.id = id;
- }else{
- throw new IllegalArgumentException("参数长度不是7位");
- }
- }
- }
上面的代码,表示就抛出了一个IllegalArgumentException类型的异常,如果在一个方法体中抛出了异常,那么就希望调用者能够去捕获异常,在Java语言中可以通过throws来声明某个方法可能会抛出的异常,这样就可以让调用者明白该方法可能会出现什么异常,要及时去捕获。
二、使用try{....}catch(){....}finally{....}捕捉异常
- try{
- //执行的代码,其中可能有异常。一旦发现异常,则立即跳到catch执行。否则不会执行catch里面的内容
- }catch (Exception e) {
- //除非try里面执行代码发生了异常,否则这里的代码不会执行
- }finally{
- //不管什么情况都会执行,包括try catch 里面用了return ,可以理解为只要执行了try或者catch,就一定会执行 finally
- }
- package com.exception;
- public class TryCatchUse {
- public static void main(String[] args) {
- try{
- System.out.println("try statement...");
- //Integer.valueOf("2");//没有异常
- Integer.valueOf("admin");//有异常
- }catch (NumberFormatException e) {
- System.out.println("catch statement...");
- e.printStackTrace();//打印出异常信息
- }finally{
- System.out.println("finally statement...");
- }
- System.out.println("after finally statement...");
- }
- }
b、如果try中出现异常,就会停止运行try中的代码,直接跳到catch中运行其中代码,catch中代码运行完后,再运行finally中的代码。
c、如果没有出现异常,但是try中存在return,或者是出现异常,但是catch中存在异常,这时finally后的代码都不会执行。
d、finally并不是捕获异常的必须部分,当我们需要关闭一些由于异常而无法关闭的资源时需要用到finally。
下面是一组结果图:
a、没有异常的try...catch...finally...,且try中或catch中都不含有return
b、有异常,但是catch中有return 的try...catch...finally...
c、没有异常,但是try中有return的try...catch...finally...
d、有异常,但是catch中没的return的情况:
总结:finally不是必须的,但是只要有finally,不管有没有异常finally中的代码都必须要执行,其次,如果try中和catch中都不主动跳出程序即都不包含return,那么不管会不会出现异常,try...catch...finally 块后面的代码都会正常执行,最后,一旦try中的某一行出现异常,就会直接跳到catch中,try中位于这一行后面的代码都不会执行。
三、自定义异常类
在程序中,可能会遇到任何标准异常类都没有能够充分地描述清楚的问题。在这种情况下,需要创建自己的异常类,这个自己定义的异常类一般都是继承Exception或者Exception的子类。通常情况下,自己定义的异常类应该有两个构造器,一个是默认的构造器,另一个是带有详细描述信息的构造器。下面就是定义自己的异常类的两种方式:
- package com.exception;
- /*当标准的异常类不能充分的描述清楚问题时,这时需要自定义异常类。
- * 自定义的异常类有两种方式
- * 一是继承Exception这个异常主类,或者是继承Exception这个主类的子类
- * 二是继承Throwable类
- * */
- public class MyException extends Exception{
- private static final long serialVersionUID = 1L;
- public MyException(){
- super();
- }
- public MyException(String msg){
- super(msg);
- }
- public MyException(String msg,Throwable cause){
- super(msg,cause);
- }
- public MyException(Throwable cause){
- super(cause);
- }
- }
- //自定义异常类的第二种方式
- class MyException_another extends Throwable{
- private static final long serialVersionUID = 1L;
- public MyException_another() {
- super();
- }
- public MyException_another(String msg) {
- super(msg);
- }
- public MyException_another(String msg, Throwable cause) {
- super(msg, cause);
- }
- public MyException_another(Throwable cause) {
- super(cause);
- }
- }