小感悟:
在学习的时候,难免会碰到各种问题,我可以用面向对象的思维来理解这个状况:
碰到问题,我们能解决吗?能解决,就try ……catch ,不能解决,就找对象(面向对象),然后——throw ,哈哈!
—————————————————————————————————————————————————————————————————————
【异常】 ——简单理解就是:不正常。这些不正常情况发生在【运行时期】。
【异常体系的由来】
程序运行时总会出现一些不正常的情况。Java语言对这些不正常情况也进行了描述,并对这些不正常进行了对象的封装。也就是说异常可以理解为:描述不正常情况的对象。【异常情况有多种,都需要分别描述,意味着异常情况应该会有一个体系】多个异常具备共性不断的向上抽取。就形成了异常体系。
【如下图所示:】
【Throwable :可抛出】
|
|--Error——有JVM从底层抛出来的问题,通常不需要处理。得修改程序。
|
|--Exception——可以定义针对的处理方式对该种情况进行处理。
无论是Error 还是Exception,他们的子类都一个特点:子类名的后缀都是父类名。 这个异常体系最大的特点:就在于该体系中的类和对象都具备可抛性。
【throws 和 throw两者区别】
throws用在函数上,用于功能声明异常,后面抛出的是异常类可以抛出多个,只要用逗号隔开即可。
throw只能用在函数内,用于抛出异常对象,额外特点,一旦执行,具有结束函数的功能。
【异常时可以处理的】——【处理方式】
1. 声明抛出。告诉调用者功能会有问题。通过throws关键字对问题声明在功能上。
2. 进行捕捉。可以使用针对性的捕捉代码块儿完成。
try
{
//需要被检测的代码。
}
catch(异常类 变量)//该变量用于检测抛出的异常对象。
{
//异常处理代码
}
finally
{
//一定会被执行的代码
}
【finally】
一定会被执行的代码。 主要用于释放资源。无论是否发生异常,有些动作一定要执行,那么这些动作定义在finally代码块儿中。
【注意:】System.exit(0);退出JVM,这时finally也不会执行。
在进行异常捕捉时,代码块的不同组合情况。
1. try catch finally
2. try catch // 没有需要一定被执行的代码——不需要关闭资源的动作。
3. try finally // 异常并没有被处理,但是却涉及到了资源的调用,资源需要被关闭。 所以就有了,将异常进行对外声明,因为没有catch,但是资源是在功能内部打开的,必须要功能内部关闭,就有了try 和 finally 的组合。
【自定义异常:】
对于常见的不正常情况,Java都有对应的描述,比如角标越界,或者空指针等。
对于自定义的程序中的出现的特有问题,Java并没有给出对应的描述。
这时需要我们队异常进行处理。
【定义方式:】
1. 定义一个类,对问题进行描述;
2.必须要让这个类继承异常类,具备可抛性。
class FuShuException extends Exception{
private int num;
FuShuException(){
super();
}
FuShuException(String message){
super(message);
}
FuShuException(String message , int num){
super(message);
this.num = num;
}
FuShuException(int num){
this.num = num;
}
public int getNum(){
return num;
}
}
class Demo11{
int div(int a , int b) throws FuShuException , ArithmeticException{
if (b < 0)
throw new FuShuException("错误,不允许 除数是负数!该负数是——>" +b);
if (b == 0)
throw new ArithmeticException("完了,被零除了!");
return a/b;
}
}
public class ExceptionDemo3 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Demo11 d = new Demo11();
try {
int x = d.div(4, -1);
System.out.println("x = " + x);
} catch (FuShuException e) {
// TODO: handle exception
System.out.println("message : " + e.getMessage());//异常信息
System.out.println("toString : " + e.toString());//异常的名字 + 信息
System.out.println("负数是 :" + e.getNum());
e.printStackTrace();// 打印异常的信息 和 名字 和 位置
}catch (ArithmeticException e){
System.out.println("message : " + e.getMessage());
System.out.println("toString : " + e.toString());
e.printStackTrace();
}
System.out.println("over");
}
}
细节:
1. 定义功能,功能内部因为传入的参数问题,导致了功能 会出现问题。这时为了解决这个问题, 通常都会将问题通过throws声明在函数上。
目的:为了调用者在使用这个功能的时候,能明确处理方式。
也就是说:throws抛出的目的是为了让调用者预先定义好问题的处理方式。
2. 如果一个功能抛出多个异常。那么在调用该功能时,需要有多个catch进行每一个异常的针对性处理;
如果多个catch中有父类异常,父类异常一定要定义在最下面。否则编译失败!
3. 特殊部分:
函数内抛出异常,函数上一定要用throws标示,否则编译失败。
调用到声明异常的函数,要进行声明throws声明抛出,或者trycatch捕捉。
异常分两种:
1.编译时被编译器检测的异常。
通常要编写针对性大的处理代码进行处理。
2.编译时不被检测的异常,这种异常出现,编译时期是不在检查之列。成为运行时异常。
也就是说函数内throw抛出运行时异常,不需要在函数上声明。即使声明了,
调用者也不用一定给出预先处理方式,因为它不会导致编译失败。
通常,不编写针对性的代码进行处理,一旦发生,就让程序停掉。
为了对代码进行修正。
【区分方式】
Exception中一个特殊的子类:RuntimeException就是运行时异常。RuntimeException和其子类都不需要编译时检测。
意味着:我们在自定义异常时,可以继承Exception,称为运行时异常。
————————————————————————————————————————————————————————————————————
异常覆盖中的细节:
1.子类在覆盖父类时,如果父类中被覆盖的方法抛出了异常,
那么子类覆盖的方法,只能抛出相同的异常,或者该异常的子类。++
2. 如果父类的被覆盖方法抛出了多个异常,子类在覆盖时,只能抛出这些异常的子集。
【3.重点掌握】 如果被覆盖的方法没有抛出异常,子类也不允许抛出异常。如果子类中真的出现异常,只能在子类方法内进行try处理,绝对不允许throws声明。 万一处理不了呢?你可以选择抛出运行时异常。