异常
一、异常概述
异常:异常就是程序在运行时出现的不正常情况,按照面向对象的思想,不正常也是事物的一部分,可以通过java类的形式进行描述,并封装成对象。其实就是java对不正常现象的封装对象描述。
通过问题的严重性对问题进行划分,对于严重的,java通过Error类来描述,通常是jvm发生的,一般编写代码进行处理,需对程序进行修正;
对于不严重的,java通过Exception类来描述,可以通过编写正对性的代码来进行处理。
以上这两个类都是Throwable(可抛)类的子类 。通过翻阅java API文档我们发现无论是Error还是Exception这两个类的子类有着一个特点:都以父类名作为子类的后缀名。 Exception需要代码处理,下面给出几个异常的举例:
数学异常,除法中除数不可为0,
package xiaobing.study;
class Demo{
int div(int a,int b){
return a/b;
}
}
public class ExceptionDemo01 {
public static void main(String[] args){
Demo d =new Demo();
int x=d.div(4, 0);
System.out.println(x);
System.out.println("over");
}
}
程序运行后出现的是:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at xiaobing.study.Demo1.div(ExceptionDemo01.java:4)
at xiaobing.study.ExceptionDemo01.main(ExceptionDemo01.java:10)
可以发现会给出具体的异常名称 :ArithmeticException,异常原因: / by zero,并且出现异常后后面的语句不会输出(over)。
二、 异常处理
1. java提供了特有的异常处理语句:
try
{
需要被检测的代码;
}
catch(异常类 变量名)
{
处理异常的代码(处理方式)
}
finally
{
一定会执行的语句
}
同时对捕获到的异常对象可以进行常见的方法操作。例如String getMessahge():获取异常的详细信息;toString():获取异常的简单描述;printStackTrace():获取异常的完整描述。
有了处理语句后上面的异常例子可以修改为:
package xiaobing.study;
class Demo1{
int div(int a,int b){
return a/b;
}
}
public class ExceptionDemo01 {
public static void main(String[] args){
Demo1 d =new Demo1();
try{
int x=d.div(4, 0);
System.out.println(x);
}catch(Exception e){//Exception e=new ArithmeticException
System.out.println("除零了");
System.out.println(e.getMessage());//bu zero
System.out.println(e.toString());//异常名称:异常信息
e.printStackTrace();//异常名称:异常信息,异常出现的位置;其实jvm默认的异常处理机制
//就是在调用printStackTrace方法
}
System.out.println("over");
}
}
2.异常的抛出。一个程序不一定会有异常或者说我们不清楚具体的异常此时可以在功能上 抛出可能出现的异常用throws关键字实现。public class void main(String[] args) throws Exception{}.
3.多异常的处理 ,程序可能存在多个异常,所以在声明异常时,建议声明具体的异常,这样异常可以处理的更具体。这里注意的是,功能抛出几个异常,就需要对应的catch代码块进行处理,如果多个catch中的异常存在继承关系,那么父类的异常catch块放在最下面如下:
package xiaobing.study;
class Demo1{
//抛出数学异常和角标越界异常
int div(int a,int b)throws ArithmeticException,ArrayIndexOutOfBoundsException
{
int[] arr=new int[a];
System.out.println(arr[4]);
return a/b;
}
}
public class ExceptionDemo01 {
public static void main(String[] args){
Demo1 d =new Demo1();
try{
int x=d.div(4, 1);
System.out.println(x);
}catch(ArithmeticException e){
System.out.println(e.toString());//异常名称:异常信息
System.out.println("被零除了");
}catch(ArrayIndexOutOfBoundsException e){
System.out.println(e.toString());//异常名称:异常信息
System.out.println("角标越界");
}
System.out.println("over");
}
}
以上需要注意,不会同时处理异常,函数中只要出现异常, 只要处理过函数就已经结束。
具体开发时,在建立catch处理时,catch中一定要定义具体的处理方式,不要简单的定义一句e.printStackTrace(),也不要
简单的书写输出语句,我们可以生成硬盘文件,即日志文件。
三、自定异常
当开发时,项目中出现了特有的问题,而这些问题并未被java所描述并封装对象,所以对于这些特有问题可以按照java的对问题的封装思想。将特有的问题进行自定义的异常封装就是自定义异常。自定义异常定义时必须继承Exception类然后用throw抛出。
举例:上述的例子除零为异常,现在我们定义除数为负数也视为异常,代码如下:
package xiaobing.study;
class FuShuException extends Exception{
}
class DemoThree{
int div(int a,int b)throws FuShuException
{
if(b<0)
throw new FuShuException();//通过throw关键字手动抛出一个异常
return a/b;
}
}
public class MyExceptionDemo {
public static void main(String[] args){
DemoThree d=new DemoThree();
try
{
int x=d.div(4, -1);
System.out.println("x="+x);
}catch(FuShuException e){
System.out.println(e.toString());
System.out.println("除数为负数了");
}
}
}
当在函数内部出现了throw抛出异常对象,那么就必须给对应的处理动作,要么在内部进行try catch 处理 ,要么在函数上声明让调用者处理。
一般情况下,函数内出现异常,函数上需要声明。
上述程序运行时我们发现 打印的结果只有异常的名称,却没有异常的信息,那么如何定义异常信息呢?
因为父类中已经把异常信息的操作都完成了,所以子类在构造时将异常信息传递给父类铜鼓super语句,那么就可以直接通过getMessage方法来获取,同时可以构造自定义
异常值代码修改如下:
class FuShuException extends Exception{
private int value;
FuShuException(String msg,int value){
super(msg);
this.value=value;
}
int getValue(){
return value;
}
}
继承Exception的原因:异常体系有一个特点,应为异常类和异常对象都被抛出,他们都具备可抛性,这个可抛性是Throwable这个体系中的独有特点,
只有这个体系中的类和对象才可以被throws和throw操作。
throws和throw关键字的区别:
throws:用在函数上,后面跟的是异常类,可以使多个,用逗号隔开
throw:使用在函数内部,后面跟的是异常对象
四、RuntimeExcption异常
Exception中有一个特殊的子类异常RuntimeException(运行时异常),如果在函数内容抛出该异常,函数上可以不用声明,编译一样通过;
如果函数上声明了该异常,调用者可以不用进行处理,编译一样通过。
之所以不在函数上声明,是因为不需要让调用者处理,当该异常发生时,希望程序停止,出现了无法继续运行的情况,希望停止程序后,对代码进行修正。
所以自定义异常时,如果该异常的发生,无法再继续运算,就让自定义异常继承RuntimeException.
class FuShuException extends RuntimeException{
private int value;
FuShuException(String msg,int value){
super(msg);
this.value=value;
}
int getValue(){
return value;
}
}
class DemoThree{
int div(int a,int b)//函数上不需要声明
{
if(b<0)
throw new FuShuException("出现除数为负数了",b);
return a/b;
}
}
练习:
package xiaobing.study;
/*
毕老师用电脑上课
上课会出现的问题:
电脑蓝屏
电脑冒烟
对问题进行描述封装成对象
可是当冒烟后出现讲课无法继续,这时就出现了教师的问题,课时无法继续
*/
class LanPinException extends Exception//该异常可以抛出处理,选择继承Exception
{
LanPinException(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=3;//定义固定状态,1表示电脑正常,冒烟1》》》3
public void run() throws LanPinException,MaoYanException
{
if(state==2)//2代表状态蓝屏
throw new LanPinException("电脑蓝屏了");
if (state==3)//3代表状态蓝屏
throw new MaoYanException("电脑冒烟了");
System.out.println("电脑运行");
}
public void reset()
{
state=1; //重启让电脑状态回到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(LanPinException e)//蓝屏异常老师可以自己处理
{
cmpt.reset();
}
catch(MaoYanException e)
{
test();
throw new NoPlanException("课时无法继续"+e.getMessage());//电脑冒烟时导致老师出现了异常
}
System.out.println("讲课");
}
public void test()//定义出现异常后备用方法
{
System.out.println("做练习");
}
}
public class ExceptionText
{
public static void main(String[] args)
{
Teacher t=new Teacher("毕老师");
try
{
t.prelect();
}
catch(NoPlanException e) //处理的是老师自己的异常,老师无法处理电脑冒烟
{
System.out.println(e.toString());
System.out.println("换老师或放假");
}
}
}