(35)异常
一、异常概念
①异常:程序在运行时出现不正常的情况
②异常由来:问题也是现实生活中一个具体的事物,也可以通过java的类的形式进行描述,并封装成对象
③对于问题的划分:两种:一种是严重的问题,一种是非严重的问题。
对于严重的,java通过Error类进行描述,对于Error一般不编写针对性的代码对其进行处理
对于非严重的,java通过Exception类进行描述,对于Exception可以使用针对性的处理方式进行描述
无论Error或者Exception都具有一些共性内容
比如:不正常情况的信息,引发原因等。
Throwable
------Error
-----Exception
二、异常的处理
java提供了特有的语句进行处理
try{ 需要被检测的代码 }
catch(异常类 变量)
{处理异常的代码 }
finally{一定会执行的语句 }
对这些语句执行流程有个简单的了解:举个栗子
若执行程序,不出异常,则会把try执行完,不会执行catch
public int div(int a,int b) {
return a/b;//出现问题:new AritchmeticException()[封装成一个对象]
}
public static void main(String[] args) {
Demo d=new Demo();
try {
int x=d.div(4, 0);//在div方法执行过程中出现了问题,并把这个问题抛给调用者:d.div(4, 0),因为有try检测机制,
// 所以,就检测到问题了。并且将这个问题丢给catch,出现问题之后的语句就不执行了,
System.out.println("x="+x);
}
catch(Exception e)//怎么接收到的呢?Exception e=new AritchmeticException();接收到,就执行处理代码
//问题检测到,并处理了,所以System.out.println("over");执行了
{
System.out.println("出现异常了");
}
System.out.println("over");
}
三、异常中catch常见的处理方法:
①
getMessage
public String getMessage()
- 返回此 throwable 的详细消息字符串。
-
- 返回:
- 此 Throwable 实例(可以为 null)的详细消息字符串。
toString
public String toString()
- 返回此 throwable 的简短描述。结果是以下字符串的串联:
- 此对象的类的 name
- ": "(冒号和一个空格)
- 调用此对象
getLocalizedMessage()
方法的结果
-
- 返回:
- 该 throwable 的字符串表示形式。
printStackTrace
public void printStackTrace(PrintWriter s)
- 将此 throwable 及其追踪输出到指定的 PrintWriter。
-
- 参数:
s
- 用于输出的PrintWriter
-
catch{
System.out.println(e.getMessage());// /by zero
System.out.println(e.toString());//异常名称:异常信息[java.lang.ArithmeticException: / by zero]
System.out.println();
e.printStackTrace();//异常名称,异常信息,异常出现的位置
//jvm默认的异常处理机制,就是在调用printStackTrace()方法
//打印异常堆栈 的跟踪信息
/*
*
java.lang.ArithmeticException: / by zero
at Demo.div(Demo.java:5)
at Demo.main(Demo.java:11)
}
四、throws Exception:对有可能出现问题的方法后面标识
便于提高安全性,让调用进行处理,不处理编译失败
public int div(int a,int b)throws Exception
/*
有时调用者可能发现不了这个函数在调用时,会出现问题,
所以,在编写函数时,在功能上通过throws的关键字声明了该功能有可能出现问题
这样,在直接调用这个函数时,系统就会提示程序员应该写trycatch语句①或者继续抛出异常②,避免一些异常的发生
*/
{
return a/b;//出现问题:new AritchmeticException()[封装成一个对象]
}
写法一①public static void main(String[] args) {
// TODO Auto-generated method stub
Demo1 d=new Demo1();
try {
int x=d.div(4, 0);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
写法二②主函数抛出异常,jvm进行处理,jvm默认的异常处理机制,就是在调用printStackTrace()方法,jvm处理异常,
程序也就结束了,出现异常后的语句,不再执行
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
Demo1 d=new Demo1();
d.div(4, 0);
}
五、对多异常的处理
①声明异常时,建议声明更为具体的异常。这样处理的可以更具体。在四中只是throws Exception,并没有明确这个异常是哪种类,型,所以应声明饿更具体些。
②对方声明几个异常,就对应有几个catch块,不要定义多余的catch块
如果多个catch块中的异常出现继承关系,父类异常catch块放在最下面
建议在catch处理时,catch中一定要定义具体的处理方式。
不要简单定义一句e.printStackTrace(),也不要简单的就书写一条输出语句(这语句没啥意义,异常还是没有解决)
public class Demo2 {
public int div(int a,int b)throws ArithmeticException,ArrayIndexOutOfBoundsException
/*
* 注意一个函数段可能会发生多个异常,可以抛出多个异常,但是不可能这些异常都被catch到,至多catch一个
* 原因是在函数中,出现异常,就会立刻返回到被调用者处,此函数之下的都不会被执行了,进而catch捕获到异常
* 执行catch后的语句.
*/
{
int[] arr=new int[a];
System.out.println(arr[4]);
return a/b;//出现问题:new AritchmeticException()[封装成一个对象]
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Demo2 d=new Demo2();
try {
int x=d.div(4, 0);
System.out.println("x="+x);
}
catch(ArrayIndexOutOfBoundsException e) {
System.out.println("角标越界"+e.toString());
}
catch(ArithmeticException e)
{
System.out.println("被零除"+e.toString());
}
System.out.println("over")
}
六、自定义异常
因为项目中会出现特有的问题,而这些问题并未被java所描述并封装对象。
所以对于这些特有的问题乐可以按照java的对问题封装的思想。
将特有的问题,进行自定义的异常封装。
当在函数内部出现了throw抛出异常对象,那么必须要给出对应的处理对象。throw new FuShuException("除数不能为负数啊!!");
要么在内部try catch处理,要么在函数上声明让调用者处理。
一般情况下,函数出现异常,函数上需要声明(throws 自定义异常类)【在调用者处用try catch或者继续抛出异常】
发现打印的结果只有异常的名称,却没有异常的信息。因为自定义的异常并未定义信息。
如何定义异常的信息呢?
方法一:
首先看throwable中构造函数:Throwable(String message)
然后看方法摘要中有个String getMessage()方法
所以想到在自定义异常类中进行复写
自定义异常类:public class FuShuException extends Exception {
private String message;
FuShuException(String message){
this.message=message;
}
public String getMessage() {
return message;
}
}
public class Demo3 {
public int div(int a ,int b) throws FuShuException(声明)
{
/*
* 自定义异常,需要抛出异常的相应的对象(catch里面接收的就是异常的对象),然后抛出
*/
if(b<0) {
throw new FuShuException("除数不能为负数啊!!");
}
return a/b;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Demo3 d=new Demo3();
try {
int x=d.div(4, -1);
}
catch( FuShuException e) {
System.out.println(e.toString());//输出:com.YiChang.FuShuException: 除数不能为负数啊!
//toString自动调用FuShuException类中的getMessage方法
}
}
}
方法二、根据继承中函数的特点,来写自定义异常类中的内容(这个是书写自定义异常类内信息的简洁方式)
在子异常类中调用父类的构造方法super(message)
这个子异常类中,还有个默认继承过来的getMessage方法,所以不用写这个方法了
简单来说:因为父类中已经把异常信息的操作都完成了。所以子类只要在构造函数是,将异常信息传递给父类通过super语句。
那么就可以直接通过getMessage方法获取自定义的异常信息
public class FuShuException extends Exception {
private String message;
FuShuException(String message){
super(message);
}
}
对上面异常的描述更具体些:
public class FuShuException extends Exception {
private String message;
private int value;//具体哪个数是异常的
FuShuException(String message,int value ){
super(message);
this.value=value;
}
public int getValue() {
return value;
}
}
public class Demo3 {
public int div(int a ,int b) throws FuShuException
{
/*
* 自定义异常,需要抛出异常的相应的对象(catch里面接收的就是异常的对象),然后抛出
*/
if(b<0) {
throw new FuShuException("除数不能为负数啊!!",b);
}
return a/b;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Demo3 d=new Demo3();
try {
int x=d.div(4, -9);
}
catch( FuShuException e) {
System.out.println("格式:异常类名:具体异常 "+e.toString());
System.out.println("异常数据是:"+e.getValue());//输出:9
}
}
}
自定义异常:
必须是自定义类继承Exception.
继承Exception类的原因:
异常体系有一个特点:因为异常类和异常对象都可抛出。
他们都具有可抛性,这个可抛性是Throwable这个体系中独有的特点。
只有这个体系中的类和对象才可以被Throws和throw操作
不是任意的类和对象可抛出的
七、throws 和throw区别
①位置:throws使用在函数上,throw使用在函数内
②throws后面跟的是异常类,可以跟多个,用逗号隔开
throw后面跟的是异常对象