黑马程序员—java基础学习--异常(exception)

时间:2022-03-03 11:50:51

日常的开发和应用中,出现异常是很常见的现象,那么,我们如何去学好异常或者说是去理解异常呢?异常什么时候使用,异常是干嘛的,异常的分类又是什么,带着这些问题,我们一起走进异常的世界,见识一下异常的奇妙。

*异常类

一、异常的概念:

异常就是程序在运行时出现的不正常情况。

二、异常的由来:

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

三、对于问题的划分:

分为两种,一种是严重的问题,一种非严重的问题。

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

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

无论Error或者Exception都具有一些共性内容,比如:不正常情况的信息,引发原因等。

Throwable

|- -Error

|- -Exception

|--RunTimeException

四、异常的处理:

java提供了特有的语句进行处理。

try{

需要被检测的代码

}catch(异常类 变量){

处理异常的代码(处理方式)

}finally{

一定会执行的语句

}

对捕获到的异常对象进行常见方法操作。其实jvm默认的异常处理机制,就是在调用printStackTrace方法,打印异常的堆栈的跟踪信息。

五、对多异常的处理:

1,声明异常时,建议声明更为具体的异常。这样处理的可以更具体。

2,对方声明几个异常,就对应有几个catch块,不要定义多余的catch块。如果多个catch块中的异常出现继承关系,父类异常catch块放在最下面。

建议在进行catch处理时,catch中一定要定义具体处理方式,不要简单的定义一句e.printStackTrace(),也不要简单的就书写一条输出语

3:理解代码如下:

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 (ArithmeticException e)
{
System.out.println(e.toString());
System.out.println("除以0了");
}
catch(ArrayIndexOutOfBoundsException e){
System.out.println(e.toString());
System.out.println("角标越界了");
}
catch(Exception e){
System.out.println(e.toString());
}
System.out.println("over");
}
}

class Demo
{
int div(int a, int b)throws ArithmeticException,ArrayIndexOutOfBoundsException {//在功能上通过throws的关键字声明了该功能会出现问题。
int[] arr = new int[a];
System.out.println(arr[4]);
return a/b;
}
}

六、自定义异常:

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

在上述程序中,对于除数是-1,也视为是错误的是无法进行运算的。那么就需要对这个问题进行自定义的描述。

当在函数内部出现了throw抛出异常对象,那么就必须要给对应的处理动作。要么在内部try catch处理,奥么在函数上生命让调用者处理。一般情况下,函数内出现异常,函数上需要声明。

自定义异常代码如下:

class FuShuException extends Exception
{
}

class Demo
{
int div(int a, int b) throws FuShuException
{
if(b<0){
throw new FuShuException();//手动通过throw关键字抛出一个自定义异常对象。
}
return a/b;
}
}

class ExceptionDemo2
{
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");
}
}

打印结果中只有异常名称,却没有异常的信息。因为自定义的异常并未定义信息。

七、如何自定义异常信息:

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

编写自定义异常必须是自定义类继承Exception。

class FuShuException extends Exception//自定义fushuException
{
private int value;
FuShuException(){
super();//通过super调用父类重的构造方法
}
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("出现了除数是负数情况。/byfushu ",b);//手动通过throw关键字抛出一个自定义异常对象。
}
return a/b;
}
}

class ExceptionDemo2
{
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("错误的负数是:"+e.getValue());
}



System.out.println("over");
}
}
自定义异常是按照java面向对象的思想,将程序中出现的特有问题进行封装。
八、继承Exception原因:

异常体系有一个特点,因为异常类和异常对象都需要被抛出,他们都具备可抛性,这个可抛性是Throwable这个体系中独有特点,只有这个体系中的类和对象才可以被throws和throw操作。

九、throws 和throw的区别:

1,throws使用在函数上,throw使用在函数内。

2,throws后面gender异常类,可以跟多个,用逗号隔开;throw后面跟的是异常对象。

十、运行时异常:

Exception中有一个特殊的子类异常RuntimeException,叫做运行时异常。如果在函数内抛出该异常,函数上可以不用声明,编译一样通过,如果在函数上声明了该异常,调用者可以不用进行处理。编译一样通过。之所以不用在函数上声明,是因为不需要让调用者处理。当该异常发生,希望程序停止,因为在运行时,出现了无法继续运算的情况,希望停止程序后,对代码进行修正。

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

十一、对于异常分为两种:

1,编译时被检测异常。

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

2,编译时不被检测的异常(运行时异常,RuntimeException以及其子类 )

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

十二、finally代码块:

定义一定执行的代码,通常用于关闭资源,因为资源必须释放。

finally只有一种情况不会执行,当执行到System.exit(0)时候,finally不会执行。

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

十三、异常在子父类中的体现:

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

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

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

当函数内容有throw抛出异常对象,并未进行try处理,必须要在函数声明,否则编译失败。注意RunTimeException除外,也就是说,函数内如果抛出的RuntimeException异常,函数上可以不用声明。

如果函数声明了异常,调用者需要进行处理,处理方法可以throws也可以try。

十四、异常的好处:

1,将问题进行封装。

2,将正常流程代码和问题处理代码相分离,方便于阅读。

十五、异常的处理原则:

1,处理方式有两种:try或者throws

2,调用到抛出异常的功能时,抛出几个,就处理几个。一个try可以对应多个catch

3,多个catch,父类的catch放在最下面

4,catch内,需要定义针对性的处理方式,不要简单的定义printStackTrace,输出语句,也不要不写。

当捕获到的异常,本功能处理不了时,可以继续在catch中抛出,如下代码:

try
{
throw new AException();
}
catch(AException e)
{
throw e;
}
如果该异常处理不了,但并不属于该功能出现的异常,可以将异常转换后,在抛出和该功能相关的异常。或者异常可以处理,当需要将异常产生的和本功能相关的问题提供出去,让调用者知道并处理,也可以将捕获异常处理后,转换新的异常。

try
{
throw new AException();
}
catch (AException e)
{
<span style="white-space:pre"></span>//对AException处理
<span style="white-space:pre"></span>throw new BException();
}