java学习过程中的异常处理方式

来源:互联网 发布:js数组转换成字符串 编辑:程序博客网 时间:2024/05/01 01:51

这两天在学习java基础中的异常,可能是以前在学校的时候没弄清楚,而且参加工作了以后在asp.net的开发中也很少用到,所以这两天学习java基础的过程中,感觉有些困难,所以在这里记录总结一下

首先,异常的概念

异常:程序在运行时出现的不正常情况

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

异常的体系

Throwable

     |----Error

     |----Exception

            |----RuntimeException


从上面可以看出,Throwable是所有异常的根类,即超类,如果object是所有类的超类一样。只有当对象是此类(或其子类之一)的实例时,才能通过jvm或者java throw语句抛出。类似的,只有此类或其子类之一才可以是catch子句中的参数类型

对于程序在运行时出现的不正常情况,可以划分成两种,一种是严重的问题,另一种是非严重的问题,分别对应异常体系中的Error和Exception

Error和Exception的区别

Error:严重的问题,java通过Error类来描述,一般不编写针对性的代码对其进行处理

Exception:对于非严重的问题,java通过Exception类来进行描述,可以使用针对性的处理方式进行处理

Errro:一般不可处理的,是由jvm抛出的严重性的问题,不作针对性处理,而是直接修改程序.

异常体系的特点

异常体系中的所有类以及建立的对象都具备可抛性。即可以被throw和throws 关键字所操作,也只有异常体系才有这个特点

throw和throws的用法和区别:

throw定义在函数内,用于抛出异常对象。后面跟的是异常对象。

throws定义在函数上,用于抛出异常类。后面跟的是异常类,可以跟多个,用逗号隔开

异常的分类

一、编译时被检测异常(编译时异常)

       该异常在编译时,如果没有处理(没有throws也没有try ),编译失败

       该异常被标识,代表可以被处理。只要是Exception及其子类都是,除了特殊子类RuntimeException体系

二、运行时异常

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

       就是Exception中的RuntimeException及其子类。

异常的处理


try{  //这里是需要被检测的代码;}catch(异常类  变量)  //该变量用于接收发生的异常对象{   //处理异常的代码;(处理方式)}finally{   //一定会被执行的语句</span>
  //特殊情况,当catch中执行System.exit(0);表示系统退出,即jvm退出。不会执行finally中的代码}

如下:

class Demo{int div(int x,int y){int[] arr=new int[x];System.out.println(arr[4]);return x/y;}}class ExceptionDemo{public static void main(String[] args){Demo d=new Demo();try{int x=d.div(4,0);System.out.println("结果:"+x);}catch(Exception e){System.out.println(e.getMessage());System.out.println(e);System.out.println(e.toString());e.printStackTrace();  //打印堆栈中的输出信息,其实JVM默认的异常处理机制,就是在调用printStackTrace()方法,打印异常在堆栈中的跟踪信息}System.out.println("over:");}}



运行结果:

其中

e.getMessage()的结果为4,e.toString()打印出的异常类为ArrayIndexOutOfBoundsException类,意思是角标越界,即在长度为4的数组中没有4这个角标

异常处理的原则:

1、函数内容如果抛出了需要检测的异常,那么函数上必须声明,如:

Demo{int div(int x,int y)throws Exception  //在函数上通过throws的关键字声明了该功能有可能会出现问题{               if(y==0)</span>                   throw new Exception();return x/y;}}



否则必须在函数内用try catch捕捉,否则编译失败

2、如果调用到了声明异常的函数(如上段代码):要么try catch 要么throws

  如图: 

上图为捕捉try catch


 上图为抛出throws

注:上图的主函数抛出异常,因为是JVM在调用主函数,所以此异常抛给了JVM,编译成功,但运行时JVM会显示异常信息

3、什么时候用try catch,什么时候throws 呢

   功能内容可以解决的,用catch。解决不了的,用throws告诉调用者,由调用者解决.

4、一个功能如果抛出了多个异常,那么调用时,必须有对应多个catch进行针对性的处理

内部有几个需要检测的异常,就抛几个异常,抛出几个,就catch几个

注:1、声明异常时,建议声明更为具体的异常,这样处理的可以更具体。2、如果多个catch块中的异常出现了继承关系,那么父类异常catch块放在最下面。3、不要定义多余的catch块

代码如下:

class Demo{//针对指定的异常:算术异常和数组角标超出异常</span>int div(int x,int y)throws ArithmeticException,ArrayIndexOutOfBoundsException  //多异常{int[] arr=new int[x];System.out.println(arr[4]);return x/y;}}class ExceptionDemo{public static void main(String[] args){Demo d=new Demo();try{int x=d.div(4,0);System.out.println("结果:"+x);}catch(ArithmeticException e) //针对算术异常(除数为0){System.out.println(e.toString());}catch(ArrayIndexOutOfBoundsException e)//针对数组角标越界异常{System.out.println(e.toString());}/*catch(Exception e)  //如果catch块中的异常出现继承关系,则父类异常catch块放在最下面{System.out.println(e.toString());}
                */
<span style="white-space:pre">System.out.println("over");}}</span>

当主函数分别调用d.div(4,0)和d.div(5,0)后的结果为:

针对上面的注意中的第2点,如图:

多个异常catch块中出现了继承关系,但是父类异常放在最上面的话,会直接用父类异常的catch块,显示捕捉到两个异常,而下面的两个子类

5、catch块内,需要定义针对性的处理方式。不要简单的定义printStackTrace输出语句,也不要不写。在实际项目中,当程序中出现异常时,通常会将异常记录到异常日志文件中。

6、当捕获到的异常,在本功能中处理不了时,可以继续在catch中抛出。

 如果该异常处理不了,但并不属于该功能出现的异常,可以将异常转换后,再抛出和该功能相关的异常。或者异常可以处理,当需要将异常产生的和本功能相关的问题提供出去,让调用者知道并处理。也可以将捕获的异常处理后,转换成新的异常

自定义异常

由来:因为项目中会出现特有的问题,而这些问题并未被java所描述并封装。所以对于这些特有的问题,可以按照java的对问题封装的思想,将特有的问题进行自定义的异常封装。

如何定义异常信息呢?

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

自定义异常继承Exception的原因:异常体系其特点是,异常类和异常对象都可以被抛出,他们都具备可抛性,这个可抛性是Throwable这个体系中的独有特点,只有这个体系中的类和对象才可以被throws和throw操作

class FuShuException extends Exception{private int value;FuShuException(String msg,int value)   //构造函数{super(msg);  //调用父类Exception的构造函数this.value=value;}public int getValue(){return this.value;}}class Demo1{int div(int a,int b)throws FuShuException  //声明{if(b<0)     throw new FuShuException("异常:除数为负!/by fushu",b);//手动通过throw关键字抛出一个自定义异常对象return a/b;}}class OwerExceptionDemo{public static void main(String[] args){Demo1 d=new Demo1();try{int x=d.div(4,-1);  //调用了声明异常的函数,那么需要调用者处理,throws或者trySystem.out.println("结果:"+x);}catch(FuShuException f){System.out.println(f.toString());System.out.println("除数出现了负数:"+f.getValue());}}}


运行时异常

Exception中有一个特殊的子类异常:RuntimeException   运行时异常

1、如果在函数内容中抛出该异常,函数上可以不用声明,编译一样通过。如下图



图1


图2

图1编译成功,而图2编译失败,其原因是:图1中抛出的ArithmeticException其父类为RuntimeException

注:之所以不用在函数上函数上声明,是因为不需要让调用者处理。当该异常发生,希望程序停止,因为在运行时,出现了无法继续运算的情况,希望停止程序后,对代码进行修正。

2、如果在函数上声明了该异常,调用中以不用进行处理,编译一样通过。 如下图:


3、自定义异常时,如果该异常的发生,无法再继续进行运算,就让自定义异常继承RuntimeException,如图



finally代码块:定义一定执行的代码,通常用于关闭资源

例如向数据库中insert 数据时发生异常,finally代码块可用于断开数据库连接

注:catch 是用于处理异常。如果没有catch就代表异常没有被处理过,如果该异常是检测时异常,那么必须声明。


异常在子父类覆盖中的体现:

1、子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法,只能抛出父类的异常或者该异常的子类

class AException extends Exception{//A 异常}class BException extends AException{//B 异常}class CException extends Exception{// C 异常}class Fu  //父类{void show()throws AException   //抛出A异常{}}class Zi extends Fu  //继承父类{void show{} throws AException   //此处只能抛出A异常或B异常,不能抛出C异常{}}

2、如果父类方法抛出多个异常,那么子类在覆盖该方法时,只能抛出父类异常的子集

3、如果父类或者接口的方法中,没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常。如果子类方法发生了异常,就必须进行try处理,绝对不能抛。


以上即为根据这两天毕老师的异常讲解视频作出的归纳和总结。

0 0
原创粉丝点击