异常
1. 定义:程序在运行时的不正常情况
2. 由来:现实生活中的一个事物也可以通过java类的形式进行描述,并封装成对象,其实就是Java对不正确情况进行描述后的对象体现
3. 问题划分
java.lang包中包括throwable类是java语言中所有错误或异常的超类,只有当对象是此类(或其子类之一)的实例时,才能通过java虚拟机或者java throw语句抛出,类似地只有此类及其子类之一才可以是catch子句中的参数类型。其中有两个.直接已知子类实例:Error和 Exception
(1)严重问题:用error描述,一般不编写针对性的代码去处理
(2)非严重问题:用exception可以使用针对性的处理方式处理。
无论error还是exception都具有共性的内容,比如不正常情况的信息,引发因素等
事例说明:
class Demo
{
int div(int a,int b)
{
return a/b;
}
}
class ExceptionDemo
{
public static void main(String[] args)
{
Demo d=new Demo();
System.out.println(d.div(4,0));
System.out.println("over");
}
}
4.异常的处理
结构:java提供了特有的语句进行处理
try
{
需要被检测的代码
}
catch(异常类 变量)
{
处理异常的代码;(处理方式)
}
finally
{
一定执行的语句
}
(1)基本程序解读
事例说明:
/**
Exception
其中的一个子类RuntimeException类的子类ArithmeticException(当出现异常算数条件时,抛出此异常)
方法:String getmessage
*/
//被java虚拟机识别问题并将问题封装成对象new ArithmeticException,并将问题抛给调用此函数的主函数
class Demo
{
int div(int a,int b)
{
return a/b;
}
}
class ExceptionDemo
{
public static void main(String[] args)
{
Demo d=new Demo();
//try检测到异常将异常抛给catch
try
{
int x=d.div(4,0);
System.out.println(x);
}
//Exception e为Exception类型的引用变量
//Exception e=new ArithmeticExcrption();
catch (Exception e)
{
System.out.println("除数为0了");
}
finally
{
System.out.println("这个程序一定会执行");
}
System.out.println("over");
}
}
(2)对捕获的异常对象进行常见方法操作
事例说明:
/**
Exception常见的操作方法
String getmessage()获取异常的信息
String toString() 异常名称 异常信息
void e.printStrackTrace异常名称,异常信息,异常出现的位置,jvm默认的异常处理机制就是调用的它。
*/
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);
}
catch (Exception e)
{
System.out.println(e.getMessage());
System.out.println(e.getMessage());
e.printStackTrace();
}
finally
{
System.out.println("这个程序一定会执行");
}
System.out.println("over");
}
}
(3)异常声明throws 在功能上通过throws的关键字声明了该功能可能出现的问题
事例说明:
class Demo
{
int div(int a,int b) throws Exception
{
return a/b;
}
}
class ExceptionDemo
{
public static void main(String[] args)
{
Demo d=new Demo();
int x=d.div(4,0);
System.out.println(x);
System.out.println("over");
}
}
不处理问题的话无法继续进行
(4)对多异常的处理
①声明异常时,建议声明更加具体的异常,这样处理更加具体。对象声明几个异常就对应几个catch块。
事例说明:
/**
ArrayIndexOutOfBoundsException用非法索引访问数组时抛出的异常。 如果索引为负或大于等于数组大小,则该索引为非法索引。
ArithmeticException(当出现异常算数条件时,抛出此异常)
*/
class Demo
{
int div(int a,int b) throws ArithmeticException,ArrayIndexOutOfBoundsException
{
int [] arr=new int [a];
System.out.println(arr[4]);
return a/b;
}
}
class ExceptionDemo
{
public static void main(String[] args)
{
Demo d=new Demo();
try
{
int x=d.div(5,1);
System.out.println(x);
}
catch ( ArithmeticException e)//算数异常
{
System.out.println("除数为0了");
System.out.println(e.toString());
}
catch(ArrayIndexOutOfBoundsException e)
{
System.out.println("角标越界了");
System.out.println(e.toString());
}
finally
{
System.out.println("这个程序一定会执行");
}
System.out.println("over");
}
}
当为int x=d.div(5,1);
当为int x=d.div(5,0);
当为int x=d.div(4,1);不管除数是否为0都不能执行
②不写多个catch块只写catch(Exception e)可以执行,但是反应的问题不具体
catch (Exception e)
{
System.out.println(e.toString());
}
同时在catch块后面也不要跟上此语句。加上这一句的情况下,程序遇到其他的问题不会终止,而会继续进行,影响对问题的纠错。另外也不要简单的加上e.printStackTrace();来处理。
(5)自定义异常
①程序中出现特有问题,而这些问题没有被java所描述并封装对象,所以对于这些问题可以按照java对问题封装思想将他们自定义封装起来
/**
需求:在程序中对于除数是负数也视为错误无法继续进行运算,那么就需要对这个问题进行自定义描述
*/
//想在打印的信息里不光只有自定义异常的名称还要加上自定义的信息
//可以通过复写Exception中的getMessage方法来实现
class FuShuException extends Exception
{
private String msg;
FuShuException(String msg)
{
this.msg=msg;
}
public String getMessage()
{
return msg;
}
}
//①一般情况下函数内出现了异常,函数上也需要声明
//②在throw FuShuException()括号中写接收的信息message
class Demo
{
int div(int a,int b) throws FuShuException
{
if(b<0)
throw new FuShuException("出现了除数是负数的情况/by fushu");
return a/b;
}
}
//当在函数内部出现了throw抛出异常对象,那么就必须要给对应的处理动作,那么内部就需要用try catch处理
//要么在函数上声明让调用者处理
class ExceptionDemo
{
public static void main(String[] args)
{
Demo d=new Demo();
try
{
int x=d.div(5,-1);
System.out.println(x);
}
catch(FuShuException e)
{
System.out.println(e.toString());
System.out.println("除数为负数了");
}
finally
{
System.out.println("这个程序一定会执行");
}
System.out.println("over");
}
}
②改进
发现在java类中有一个Throwable(String message),父类中有这么一个方法,而且它提供了getMessage的方法
可以推理得:
class Trowable
{
private String message;
Trowable(String message)
{
this.message=message;
}
public String getMessage()
{
return message;
}
}
另外发现他的子类Exception没有方法,但有构造函数Exception(String message)
class Exception extends Throwable
{
Exception(String message)
{
//父类既然做完了,子类就可以直接获取,因为既然父类已经把异常信息的操作都完成了,所以子类只要在构造时将异常信息通过super语句传给父类,那么就可以通过个体getMessage方法获取自定义的异常。
super(messsage);
}
}
//然后new Exception().getMessage就可以获取信息
最终程序可以改为
class FuShuException extends Exception
{
FuShuException(String msg)
{
super(msg);
}
}
③改进:
想知道负数值
//自定义一个变量参数来获取负数值
class FuShuException extends Exception
{
private String msg;
private int value;
FuShuException(String msg,int value)
{
super(msg);
this.value=value;
}
public int getValue()
{
return value;
}
}
class Demo
{
int div(int a,int b) throws FuShuException
{
if(b<0)
throw new FuShuException("出现了除数是负数的情况/by fushu",b);//注意此处传的是b
return a/b;
}
}
class ExceptionDemo
{
public static void main(String[] args)
{
Demo d=new Demo();
try
{
int x=d.div(5,-1);
System.out.println(x);
}
catch(FuShuException e)
{
System.out.println(e.toString());
System.out.println("除数为负数了"+e.getValue());
}//此处获取b值
finally
{
System.out.println("这个程序一定会执行");
}
System.out.println("over");
}
}
④总结1:自定义异常必须是自定义异常继承Exception,但是为什么不继承throwable?
异常体系有一个特点,因为异常类和异常对象需要被抛出,他们都具有可抛性,这个可抛性是throwable这个体系所独有的特点。至于这个体系中的类和对象才可以被throws和throw操作。
⑤总结2:throws和throw的区别?
throws试用在函数上,后面跟的是异常类,可以跟多个用逗号隔开
throw试用在函数内,后面跟的是异常对象
(6)RuntimeException
RuntimeException有子类ArithmeticException其中有构造方法ArithmeticException()和ArithmeticException(String s)
RuntimeException的异常若在函数上被抛出了,在函数上不用声明
原因:声明是希望对方处理,对方若给出响应的处理方式那么问题就会被隐藏了(错误数值时,能运行但只能看到出现异常的信息)若不声明则不知道其有问题,则不会处理,则只要传错值,程序就会终止,希望代码修改(错误数值时,程序不能运行,只有把数值修改完成之后才能继续运行)。
事例说明:
/**
若b=0不能运行,主函数中的x=d.div(4,0);x不能获得值,jvm希望不处理,要将程序停掉,修改数值。
*/
class Demo
{
int div(int a,int b)
{
if(b==0)
throw new ArithmeticException("被0除了");
return a/b;
}
}
总结:若自定义异常,如果该异常的发生无法再继续运算就让自定义异常继承RuntimeException。
(7)finally应用
存放的是一定执行的代码,通常用于关闭资源。只有在一种情况下finally不执行,当catch中有Sysem.exit(0);(系统推出,jvm结束)时,finally语句不执行。
class SQLException extends Expection
{
}
public void method() throws NoException
{
连接数据库;
数据库操作;
关闭数据库;//该操作无论操作是否成功,一定要关闭资源
try
{
连接数据库;
数据操作;
}
catch (SQLException e)
{
会对数据进行处理;
throw new NoException;//另外注意分层思想,只暴
// 露对功能识别的功能
}
finally
{
关闭数据库;
}
}
(8)异常处理的其他格式
①try ②try ③try
{ { {
} } }
catch finally catch
{ { {
} } }
finally
{
}
(9)异常在子类覆盖中的体现
①子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法只能抛出父类的异常或是该异常的子类
事例说明:
class AException extends Exception
{}
class BException extends AException
{}
class CException extends Exception
{}
class Fu
{
void show() throws AException
{}
}
class Zi extends Fu
{
void show() throws AException/BException/不可以CException
{}
}
class Test
{
void function(Fu f)
{
try
{
f.show()
}
catch (AExceptin e)
{}
}
}
class Demo1
{
public static void main(String[] args)
{
Test t=new Test();
t.function(new Zi());
}
}
②如果父类方法抛出多个异常,那么子类在覆盖该方法时,只能抛出父类异常的子集。
③如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时也不可以抛出异常。如果子类方法发生了异常就必须进行try处理,绝对不能抛。
5.事例说明讲解
/**
需求:有一个圆和长方形,都可以获取面积,对于棉结出现非法数值时,被视为获取面积的时候出现问题,即异常。
思想:圆和长方形都有面积的属性,属于扩展属性,所以可以将它们定义成接口,提取出一个抽象类
*/
//自定义异常NovalueException
class NoValueException extends RuntimeException
{
NoValueException(String msg)
{
super(msg);
}
}
//定义接口,提取抽象类
interface Shape
{
void getArea();
}
//定义圆的类继承接口Shape并重写getArea()方法
class Circle implements Shape
{
private int radius;
public static final double PI=3.1415;
Circle(int radius)
{
if(radius<=0)
throw new NoValueException("Wrong radius");
this.radius=radius;
}
public void getArea()
{
System.out.println(radius*radius*PI);
}
}
//定义长方形类继承接口Shape并重写getArea()方法
class Rec implements Shape
{
private int len,wid;
Rec(int len,int wid)//throws NoValueException
{
if(len<=0||wid<=0)
throw new NoValueException("Wrong len or wid");
this.len=len;
this.wid=wid;
}
public void getArea()
{
System.out.println(len*wid);
}
}
class Demo1
{
public static void main(String[] args)
{
//建立圆和长方形的对象
Rec r=new Rec(2,3);
Circle c=new Circle(-2);
r.getArea();
c.getArea();
System.out.println("over");
}
}
Rec r=new Rec(2,3);Circle c=new Circle(2);时
Rec r=new Rec(-2,3);Circle c=new Circle(-2);时
Rec r=new Rec(2,3);Circle c=new Circle(-2);时
另外注意自定义异常时NoValueException继承Exception和继承RuntimeException的区别
//自定义异常NovalueException
class NoValueException extends Exception
{
NoValueException(String msg)
{
super(msg);
}
}
//定义接口,提取抽象类
interface Shape
{
double getArea();
}
//定义圆类继承接口Shape并重写getArea()方法
class Circle implements Shape
{
private int radius;
public static final double PI=3.1415;
Circle(int radius)throws NoValueException
{
if (radius<=0)
throw new NoValueException("Wrong radius");
else
this.radius=radius;
}
public double getArea()
{
return radius*radius *PI;
}
}
//定义长方形类继承接口Shape并重写getArea()方法
class Rec implements Shape
{
private int len,wid;
Rec(int len,int wid) throws NoValueException
{
if(len<=0||wid<=0)
throw new NoValueException("Wrong len or wid");
else
{
this.len=len;
this.wid=wid;
}
}
public double getArea()
{
return len*wid;
}
}
class Demo1
{
public static void main(String[] args)
{
try
{
//建立圆或者是长方形的对象
Rec r=new Rec(3,2);
Circle c=new Circle(3);
System.out.println(c.getArea());
System.out.println(r.getArea());
}
catch (NoValueException e)
{
System.out.println(e.toString());
}
}
}
Rec r=new Rec(3,2);Circle c=new Circle(3);时
Rec r=new Rec(-3,2);Circle c=new Circle(3);时
Rec r=new Rec(3,2);Circle c=new Circle(-3);时