JavaSE学习笔记_8:Java异常

来源:互联网 发布:知敬畏守底线心得体会 编辑:程序博客网 时间:2024/06/05 20:11

Java异常

 

程序在运行的过程中可能产生问题。对于问题的可以划分成两种:一种是严重的问题,一种是非严重的问题。

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

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

无论Error或者Exception都具备一些共性内容。

比如:不正常情况的信息,引发原因等。这两个类就可以向上抽取出一个类,形成一个体系。

Throwable

|--Error

|--...

|--Exception

|...

异常和错误的情况注意区分。

 

异常:就是其中一种问题。它是程序在运行的时候出现的不正常情况。

 

异常的由来:问题也是现实生活中一个具体的事物个体。它们也有共性,因此可以进行描述抽取成一个类。这个类就叫做异常类。

 

异常可以分为:java能够识别的异常和用户自定义的异常。

1、java能够识别的异常。

比如ArithmeticException。除数不能为0。

看下面的代码:

class Demo

{

int div(int a,int b)

{

return a/b;

}

}

class ExceptionDemo

{

public static void main(String[] args)

{

Demo d=new Demo();

int x=d.div(4,1);

System.out.println(“x=”+x);

System.out.println(“over”);

}

}

上述代码是没有问题的,正常运行出结果。但是当传入的是4,0;编译通过,但运行失败。因为运行的时候才回去算。运行时显示出一大堆信息。虚拟机默认的处理机制。问题丢给虚拟机,虚拟机就会这样处理。下面我们有java提供的特有语句进行处理。

(1)第一种格式:

try

{

需要被检测的代码;

}

Catch(Exception e)

{

处理的代码;

}

finaly

{

一定会执行的语句。

}

(2)第二种格式:

try

{

需要被检测的代码;

}

Catch(Exception e)

{

处理的代码;

}

(3)第三种格式:

try

{

需要被检测的代码;

}

finaly

{

一定会执行的语句。(即使是程序遇到return或者是throw等程序结束标志,也会执行。唯一一种情况就是程序遇到System.exit(0),不会执行。)

}

这里插入一下:final有什么用?

看一需求:客户端-程序访问数据库,而数据库在服务器(一台主机),访问数据就得连接数据库,连完后,过一段时间必须断开连接。因为服务器是一台主机,主机中就有cpu,cpu处理的程序是有限的,则必须连接之后,一段时间断开让其他客户端来连接访问数据库,所以,不敢有没有从数据库中取出数据都的断开连接。

例如:

public void method()

{

连接数据库;

数据操作;

关闭数据库;

}

增,删,改,查,可能会出现一些问题,如要删除的数据不存在。throw SQLException();抛完异常,程序就结束了,则关闭操作就没有被执行到。因此,没问题,能按顺序执行到,关闭数据库。出了问题就关闭不了,就在耗费资源。则:关闭数据库动作,无论数据操作是否成功,一定要关闭资源。

public void method()

{

try

{

连接数据库;

数据操作;

}

catch(SQLException e)

{

 

}

finally

{

关闭数据库;

}

}

/*

finally代码:定义一定执行的代码。

通常用于关闭资源。

*/

 

(4)第四种格式:

try

{

需要被检测的代码;

}

Catch(Exception e)

{

处理的代码;

}

Catch(Exception e)

{

处理的代码;

}

 

 

代码如下:

class Demo

{

int div(int a,int b)

{

return a/b;

}

}

class ExceptionDemo

{

public static void main(String[] args)

{

Demo d=new Demo();

try

{

int x=d.div(4,0);

System.out.println(“x=”+x);

}

Catch(Exception e)

{

System.out.println(“除0了”);

}

System.out.println(“over”);

}

}

看图进一步掌握:

 

 

可以对捕获到的异常对象进行常见方法操作:

class Demo

{

int div(int a,int b)

{

return a/b;

}

}

class ExceptionDemo

{

public static void main(String[] args)

{

Demo d=new Demo();

try

{

int x=d.div(4,0);

System.out.println(“x=”+x);

}

Catch(Exception e)

{

System.out.println(“除0了”);

 

//打印异常信息。Java能识别的异常有异常信息。

//如果是自定义异常,则需要自己定义异常信息。

// /by zero

System.out.println(e.getMessage());

 

//打印异常名、异常信息

//java.lang.ArithmeticException:/by zero

//如果是自定义类的异常信息,异常类名前面没有

//java.lang

//可知,toString()调用了getMessage()

System.out.println(e.toString());

 

//打印异常名、异常信息、异常位置。分行打印。

//java.lang.ArithmeticException:/by zero

//java.lang.ArithmeticException:/by zero

//at Demo.div(Exception.java.50)

      //atExceptionDemo.main(ExceptionDemo.java:62)

//虚拟机默认的处理机制就是调用这个方法。

e.printStackTrace();

}

System.out.println(“over”);

}

}

 

 

 

通常功能可能有问题,我们必须要在函数上声明。利用关键字throws,功能内可能会发生什么异常就声明什么什么异常,当然你也可以声明Exception,但是这样调用者不知道具体会发生什么问题,处理的也会没有针对性,因此,建议声明的具体一些,这样处理的也就具体一些。当我们在函数这样声明了,就表示告诉调用者这个功能是有可能发生问题的。强制调用者必须在调用的时候进行处理,否则会编译失败。处理有两种方式:一种是通过try{}catch(){},一种是继续在它的函数头上声明向它的上一级抛。告诉它的上一级他可能会发生异常。异常可以逐级向上抛,抛到java虚拟机就到头了。||对于多异常,一个功能可能会发生多个问题。也是类似的解决办法。唯一要注意的就是,对方声明几个异常,(这几个异常用逗号隔开)就对应有几个catch块,不要多定义。如果你非要再加个catch(Exception e){},这个catch块只能放在最后,否则只要发生异常,不管什么异常都由它处理了,其他若干个catch等于废话,永远执行不到,编译会失败。

 

温馨提示:建议在进行catch处理的时候,catch中一定要定义具体的处理方式。不要简单的定义一句e.printStackTrace(),或者简单的书写一条输出语句。那样的话还不如不解决(声明+处理),发生问题直接让虚拟机启动它的默认处理机制。而且,你这样用户也看懂。真发生了问题,我们会用一个硬盘文件记录下来,称之为异常日志文件。管理员/网站维护人员回去看,会去解决,调试。我们在学习异常的时候,打印是为了方便。

 

2、开发员自定义的异常。

比如:FushuException.功能中我们不允许发生的事(如除数不能为负数)、和实际情况不符合的事(如求面积不能为负)可能发生。就会产生一个问题。我们就自己定义一个异常类。在异常类出现之前,我们对此的解决办法就是通过if-else语句进行判断,但是这将会导致问题处理代码(if(){})和正常流程代码(else{})联系紧密,聚集在一起阅读起来很痛苦,因此异常的出现能让问题处理代码和正常流程代码相分离。

自定义异常和java识别的异常唯一区别就是:问题发生时需要手动抛出异常。利用关键字throw,如:

throw new FushuException();

(这里注意:throw和return一样也是程序结束的标志,后面不能再有语句。否则编译失败。)

唯一的特殊之处:手动抛出的异常如果在内部解决掉,函数上就不要再声明,向调用者抛。如:

class Demo

{

public void method()

{

try

{

throw new Exception();

}

catch(Exception e)

{

try

{

throw e;

}

catch()

{

}

}

}

}

其他的地方和java能够识别的异常使用相同。

 

自定义异常类必须继承Exception。Throwable这个体系有一个特点:异常类和异常对象都具备可抛性。

 

实例:

class FushuException extends Exception

{

 

}

class Demo

{

int div(int a,int b)

{

if(b<0)

Throw new FushuException();

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(FushuException e)

{

System.out.println(e.toString());

System.out.println(“除数出现负数”);

}

System.out.println(“over”);

}

}

运行结果:

FushuException

除数出现负数了

Over

 

如何定义异常信息?

我们知道:

class Throwable 

{

private String message;

Throwable()

{

 

}

Throwable(String message)

{

this.message=message;

}

public String getMessage()

{

return message;

}

}

 

 

class Exception extends Throwable

{

private String message;

Exception()

{

 

}

Exception(String message)

{

//this.message=message;父类已做,自类没必要再做

super();

}

}

 

因此,对于自定义异常类,可以这么定义异常信息:

class FushuException extends Exception

{

//自定义异常也可以没有异常信息

FushuException()

{

}

FushuException(String message)

{

This.message=message;

}

}

class Demo

{

int div(int a,int b)

{

if(b<0)

Throw new FushuException();

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(FushuException e)

{

System.out.println(e.toString());

System.out.println(“除数出现负数 /by fushu”);

}

System.out.println(“over”);

}

}

运行结果:

FushuException:除数出现了负数 /by fushu

Over

 

当然我们还可以在自定义异常类中定义其他的功能。

 

3、RuntimeException

(1)对于继承了RuntimeException的java能够识别的异常类:

如果在函数上声明了,调用者可以不用解决,照样编译通过。这样的类有:ArithmeticException,ArrayIndexOutofBoundException、NullPointerException等。

(2)对于继承了RuntimeException的开发员自定义的异常类:

① 如果在函数内抛出了异常,函数上可以不用声明,编译一样通过。

② 如果在函数上声明了,调用者可以不用解决,照样编译通过。

 

对于(1)和(2)中的第二条,我们干脆就不声明了,因为你声明了,调用这就会习惯性去解决,虽说是解决了,但可能没有实质性的解决掉。这样等于将问题隐藏了。因此:自定义异常类时,如果该异常发生,程序无法再继续进行,我们想让程序停掉。那么我们就让自定义异常类继承RuntimeException。这样问题最后抛向了虚拟机。启动默认处理机制。

 

说到这:

对于异常又可以分为:

1、编译时被检测的异常。(可处理,需处理)

2、编译时不被检测的异常。(运行时异常)(不可处理)

 

4、异常经典示例

(1)毕老师用电脑上课

class Computer

{

public void run()

{

System.out.println(“电脑运行”);

}

public void reset()

{

System.out.println(“电脑重启”);

}

}

class Teacher

{

private String name;

private Computer cmpt;

Teacher(String name)

{

this.name=name;

cmpt=new Computer();

}

public void prelect()

{

cmpt.run();

System.out.println(“讲课”);

}

}

class ExceptionTest

{

public static void main(String[] args)

{

Teacher t=new Teacher(“毕老师”);

T.prelect();

}

}

编译运行:

电脑运行

上课

 

/*

开始思考上课中出现的问题。应该是电脑出现了问题,而不是老师。

比如:

电脑蓝屏

电脑冒烟

要对问题进行描述,封装成对象。

*/

class LanPingException extends Exception

{

LangPinException(String message)

{

super(message);

}

}

class MaoYanException extends Exception

{

MaoYanException(String message)

{

super(message);

}

}

class Computer

{

private int state=1;

public void run()

throws LanPinException,MaoYanException

{

if(state==2)

throw new LanPinException(“蓝屏”);

if(state==3)

throw new MaoYanException(“冒烟”);

}

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 MaoYanException

{

try

{

cmpt.run()

}

catch(LanPinException e)

{

cmpt.reset();

}

catch(MaoYanException e)

{

throw e;

}

System.out.println(“讲课”);

}

}

class ExceptionTest

{

public static void main(String[] args)

{

Teacher t=new Teacher(“毕老师”);

Try

{

T.prelect();

}

catch(Exception e)

{

 

}

}

}

那么问题来了,这个冒烟的问题抛给了main(),它也不能处理。两者没有直接的关系。因此,在prelect()中的第二个catch就不能抛出e。那怎么办呢?把冒烟的异常转化成授课老师的异常在抛给main()去处理。具体为:电脑冒烟,老师就不能讲课,因此老师就产生了异常。

 

/*

当冒烟发生后,出现讲课进度无法继续。

出现了讲师问题:课时无法完成。

*/

class LanPingException extends Exception

{

LangPinException(String message)

{

super(message);

}

}

class MaoYanException extends Exception

{

MaoYanException(String message)

{

super(message);

}

}

//定义新异常类

class NoPlanException extends Exception

{

NoPlanException(String message)

{

super(message);

}

}

class Computer

{

private int state=1;

public void run()

throws LanPinException,MaoYanException

{

if(state==2)

throw new LanPinException(“蓝屏”);

if(state==3)

throw new MaoYanException(“冒烟”);

}

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 MaoYanException

{

try

{

cmpt.run()

}

catch(LanPinException e)

{

cmpt.reset();

}

catch(MaoYanException e)

{

test();

//解决不了,继续抛。

//解决得了,继续抛。抛和该功能相关的异常。

throw new NoPlanException(“课时无法继续”);

}

System.out.println(“讲课”);

}

public void test()

{

System.out.println(“lianxi”);

}

}

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(“换电脑或者换老师,不然就放假”);

}

}

}

(2)求图形面积

interface Shape

{

void getArea();

}

class Rec implements Shape

{

private int len,wid;

Res(int len,int wid)

{

this.len=len;

this.wid=wid;

}

public void getArea()

{

System.out.println(len*wid);

}

}

class ExceptionTest

{

public static void main(String[] args)

{

Rec r=new Rec(3,4);

r.getArea();

}

}

运行结果:

12

传入(3,-4)

运行结果:

-12

问题:这与现实生活中的情况不符合。于是我们用以前常用的方法来解决:

interface Shape

{

void getArea();

}

class Rec implements Shape

{

private int len,wid;

Res(int len,int wid)

{

if(len<=0||wid<=0)

System.out.println(“非法”);

else

{

this.len=len;

this.wid=wid;

}

}

public void getArea()

{

System.out.println(len*wid);

}

}

class ExceptionTest

{

public static void main(String[] args)

{

Rec r=new Rec(3,4);

r.getArea();

}

}

这种解决方案使得正常流程代码和问题处理代码聚集在一起。阅读性很差。因此定义异常类:

class NoValueException extends Exception

{

NoValueException(String message)

{

super(message);

}

}

interface Shape

{

void getArea();

}

class Rec implements Shape

{

private int len,wid;

Res(int len,int wid)throws NoValueException

{

if(len<=0||wid<=0)

Throw new NoValueException(“出现非法值”);

else

{

this.len=len;

this.wid=wid;

}

}

public void getArea()

{

System.out.println(len*wid);

}

}

class ExceptionTest

{

public static void main(String[] args)

{

try

{

Rec r=new Rec(3,4);

r.getArea();

}

catch(NoValueException e)

{

System.out.println(e.toString());

}

System.out.println(“over”);

}

}

但是这个问题其实我们不应该去处理,处理不当等于将问题隐藏,我们应该根据异常信息去改动程序。因此应该让NoValueException继承RuntimeException。如下所示:

class NoValueException extends RuntimeException

{

NoValueException(String message)

{

super(message);

}

}

interface Shape

{

void getArea();

}

class Rec implements Shape

{

private int len,wid;

Res(int len,int wid)throws NoValueException

{

if(len<=0||wid<=0)

Throw new NoValueException(“出现非法值”);

else

{

this.len=len;

this.wid=wid;

}

}

public void getArea()

{

System.out.println(len*wid);

}

}

class ExceptionTest

{

public static void main(String[] args)

{

Rec r=new Rec(3,4);

r.getArea();

}

}

 

 

5、异常—覆盖时的异常特点

(1)子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法,只能抛出父类的异常或者该异常的子类。或者不抛。若在子类中抛出其他异常,只能在内部解决,不能throws声明出去。

(2)如果父类方法抛出多个异常,那么子类在覆盖该方法时,只能抛出父类异常的子类。或者不抛。若在子类中抛出其他异常,只能在内部解决。不能throws声明出去。

(3)如果父类或者接口的方法中没有异常抛出,那么子类在覆盖该方法时,也不可以抛。如果子类方法可能发生异常,只能在内部解决,不能throws声明出去。

 

其实:这些规定都是由于,声明时父类声明了具体的异常,如果声明的是根异常类Exception,则没有这些规定。

 

示例:看图

 

 

 

 

 


2015-11-222015-11-24

0 0
原创粉丝点击