2.8Java异常

1.定义:
异常:是在运行时期发生的不正常情况。
异常类:在java中用类的形式对不正常情况进行了描述和封装对象。描述不正常的情况的类,就称为异常类

以前正常流程代码和问题处理代码相结合,
现在将正常流程代码和问题处理代码分离,提高阅读性。

2.体系:
问题一多,类就越多。
将其共性向上抽取,形成体系:

Throwable: 父类,无论是error,还是异常,都是问题,问题发生就可以抛出,让调用者知道并处理。

该体系的特点:就在于Throwable及其所有的子类都具有可抛性。子类的后缀名都是用其父类名作为后缀,阅读性很强。
可抛性的体现:通过两个关键字来体现:thorws,throw。凡是可以被这两个关键字所操作的类和对象都具有可抛性。

3.问题的分类:
最终问题就分成了两大类:

1.一般不可处理。Error
特点:是由jvm抛出的严重性的问题。
这种问题发生一般不针对性处理。直接修改程序。

2.可以处理的。Exception

例子:

class  ExceptionDemo1
{
    public static void main(String[] args) 
    {

    }

    public static void sleep(int time)
    {
        if(time<0)
        {
            抛出 new FuTime();    //就代表着时间为负的情况,这个对象中会包含着问题的名称,信息,位置等信息。
        }
        System.out.println(time);
    }
}

class FuTime    //异常类
{

}

4.异常原理:
异常原理

例子:

/*
异常原理

*/
class Demo
{
     int method(int[] arr, int index)
    {
 /*     //②可以自己产生异常

         if(arr == null)    
                throw new NullPointerException("数组引用不能为空");

         if(index >= arr.length)      
        {
            throw new ArrayIndexOutOfBoundsException("数组角标越界");
         }
*/



        return arr[index];     //①默认会进行异常对象封装:throw new ArrayIndexOutOfBoundsException(index)
                                                                                //程序终止,下面的代码不再执行        
    }
    }

class ExceptionDemo2 
{
    public static void main(String[] args) 
    {
        int[] arr = new int[3];
        Demo d = new Demo();
        int num = d.method(null,3);         //异常抛出到这里,然后主函数又丢给虚拟机。虚拟机执行异常处理机制,把异常信息打印。
                                                    //可惜用户看不懂
                                                    //程序终止,下面的代码不再执行
        System.out.println(num);
    }

}

5.自定义异常: 声明 throws

注意点:如果让一个类称为异常类,必须要继承异常体系,因为只有成为异常体系的子类,才有资格具备可抛性。
才能被两个关键字所操作,throws,throw

异常的分类:

1.编译时被检测异常:Exception和其子类都是,除了特殊子类RuntimeException体系。(需要异常声明throws处理)
如:自定义异常FuShuIndexException

这种问题一旦出现,希望在编译时就进行检查,让这种问题有对应的处理方式。


2.编译时不检查异常:Exception的特殊子类RuntimeException及其子类。(它们在编译时不需要异常声明处理)
如:数组越界异常ArrayIndexOutOfBoundsException,空指针异常NullPointerException等。(遇到较多)

这种问题的发生,无法让功能继续,运算无法进行,更多是因为调用者的原因导致的或者引发了内部状态的改变导致的。
那么这种问题一般不处理,直接编译通过,在运行时,让调用者调用时的程序强制停止,让调用者对代码进行修正。

所以自定义异常时,要么继承Exception,要么继承RuntimeException。

throws 和throw的区别:

1.throws 使用在函数上
    throw 使用在函数内

2.throws抛出的是异常类,可以抛出多个,用逗号隔开
    throw 抛出的是异常对象。

例子:

/*
自定义异常:声明 throws

举例:对于负数角
标这种异常java中没有定义过。
那么,就按照java异常的创建思想,面向对象,将负数角标进行自定义描述,并封装成异常类。

java先检查语法错误,才会检查逻辑错误。异常最后报错。
*/
class FuShuIndexException extends Exception
{
    FuShuIndexException()
    {
    }
        FuShuIndexException(String msg)
    {
                super(msg);          //调用的父类的构造方法。
    }
}

class Demo
{
    int method (int[] arr, int index) throws FuShuIndexException   //要在函数声明后添加   异常声明
    {
        if(index <0)
            throw new FuShuIndexException("数组角标负数异常");     //错误:未报告的异常错误FuShuIndex; 必须对其进行 捕获 或 声明 以便抛
        return arr[index];  
    }
}


class ExceptionDemo3 
{
    public static void main(String[] args) throws FuShuIndexException   //添加 异常声明
    {
        int[] arr = new int[3];
        Demo d = new Demo();
        int i = d.method(arr,-1);    //使用了异常声明函数,也必须在函数上添加 异常声明
        System.out.println(i);
    }
}

6.异常自定义处理: 捕捉

这是可以对异常进行 针对性 处理方式。

具体格式:

try
{
    //需要被检测异常的代码
}
catch(异常类 变量)  //接收发生异常的对象
{
    //处理异常的代码
}

finally
{
    //一定会被执行的代码
}
这个问题如果自己不能处理,就用throws

如果自己可以处理,就用try

例子:

class FuShuIndexException extends Exception
{
    FuShuIndexException()
    {
    }

    FuShuIndexException(String msg)
    {
        super(msg);
    }
}

class Demo 
{
    int method(int[] arr, int index)   throws FuShuIndexException,NullPointerException   //如果抛出了多个异常,则需要多catch
    {
        if(arr == null)
            throw new NullPointerException();
        if(index <0)
            throw new FuShuIndexException("数组角标为负数!");
        return arr[index];
    }
}


class  ExceptionDemo4
{
    public static void main(String[] args)     //如果异常自己解决不了,就抛出去throws,给虚拟机执行.printStackTrace()。
    {
        int[] arr = new int[3];

        Demo d = new Demo();    
        try
        {
                int i = d.method(null,0);        //异常抛在这里,new FuShuIndexException("数组角标为负数!");
                System.out.println(i);  

        }
        catch (FuShuIndexException f)     //接收抛来的异常对象,而不是直接给虚拟机了。
                                                                            //FuShuIndexException f = new FuShuIndexException("数组角标为负数!");
        {


            System.out.println(f.getMessage());       //可以使用异常对象,及其父类的所有方法,打印需要的异常信息
                                                    //输出异常信息
            System.out.println(f);                 //该对象不是类型和哈希值,(f.toString())异常对象有建立自己的独特字符串类型(可以该的,其实是默认加了toString()方法)。
                                                    //输出异常类名 + 异常信息
            f.printStackTrace();       //输出异常类名 + 异常信息 ,及其追踪输出。 注意返回值是空类型,不要直接打印。
                                                    //jvm默认的异常处理机制就是调用异常对象的这个方法。




            System.out.println("负数角标异常!");      //自行处理方式
        } 

/*      catch()      //多异常多catch
        {

        }*/

        catch(Exception e)    //如果为了检测其他异常,父类的catch应该放最后,因为是按顺序检测。而所有异常对象都属于Exception。
                                                //多catch时面试会问。
        {                                           
                e.printStackTrace();
        }
        System.out.println("over");     //程序继续运行
    }
}

//通常建立日志文件用第三方工具,如 log4j(log for java)

多catch情况:父类的catch应该放最后,因为是按顺序检测。而所有异常对象都属于Exception。

7.异常处理原则:

1.函数内部如果抛出需要检测的异常,那么函数上必须要声明。
    否者必须在函数内用trycatch捕捉,否者编译失败。
2.如果调用到了声明异常的函数,要么trycatch,要么throws,否者编译失败。
3.功能内部可以解决,用catch.
解决不了,用throws告诉调用者,由调用者解决。
4.一个功能如果抛出了多个异常,那么调用时,必须对应多个catch进行针对性的处理。
内部有几个需要检测的异常,就抛几个异常。抛出几个,就catch几个。

8.finally代码块:
1)作用举例:

连接数据库。
查询。      Exception
关闭连接。  一定要执行,放在finally代码块里。

2)代码块组合:

1.try catch finally
2.try catch(对个)    当没有必要资源需要释放时,可以不用定义finally

3.try finallycatch就没有处理,所以还是要在函数上throws声明异常来处理。

用处:异常先不处理,但是资源得关掉。

void show() throws Exception
{
        try
        {
                //开启资源
                throw new Exception();
                //这里无法关闭资源,因为执行不到
        }
        finally
        {
                //关闭资源
        }
}

3)例子:

class Demo
{
    int show(int index)
    {
        if(index < 0)
            throw new ArrayIndexOutOfBoundsException("越界了!");
        int[] arr = new int[3];
        return arr[index];
    }
}


class  ExceptionDemo5
{
    public static void main(String[] args) 
    {
        Demo d = new Demo();


        try
        {
             int num = d.show(-3);
            System.out.println(num);
        }
        catch (ArrayIndexOutOfBoundsException e)
        {
                System.out.println(e.toString());
                return;                  //如果System.exit(0); 推出jvm,这时finally不执行
        }
        finally
        {
                System.out.println("finally");     //函数结束,也会执行
        }


        System.out.println("over");    //函数如果提前结束,不会执行
    }
}

9.异常的应用:

/*
异常的应用:   异常转换:不要有什么异常就抛出什么异常,要看调用者能否处理。

void addData(Data d)    throws  Exception         //不抛出数据库异常,因为调用者不懂数据库。
                                                                                        //进行异常转换,抛出调用者可以处理的异常。
{
    连接数据库。
    try
    {
        添加数据。出现异常 SQLException();
    }
    catch(SQLException e)
    {
        处理数据库异常。
        throws new Exception("数据没有添加成功");   //可以自定义异常抛出
    }
    finally
    {
        关闭数据库。
    }

}






毕老师用电脑上课。

问题领域中涉及两个对象。
毕老师,对象。

分析其中的问题:

比如电脑蓝屏,冒烟了。

*/

class LanPingException extends Exception
{
        LanPingException(String msg)
    {
            super(msg); 
    }
}

class MaoYanException extends Exception
{
        MaoYanException(String msg)
            {
                super(msg);
        }
}

class  prelectStop extends Exception
{
        prelectStop(String msg)
        {
                super(msg);
        }
}

class Computer 
{
    private int state = 2;
    void run() throws LanPingException,MaoYanException
    {
        if(state == 1)
            throw new LanPingException("电脑蓝屏了!");
        if(state == 2)
            throw new MaoYanException("电脑冒烟了!");

        System.out.println("电脑运行");
    }

    void reset()
    {
        state = 0;
        System.out.println("电脑重启");
    }
}

class Teacher
{
    private String name;
    private Computer comp;
    Teacher(String name)
    {
        this.name = name;
        comp = new Computer();
    }

    void prelect()   throws prelectStop  //  throws MaoYanException   //老师讲课抛出电脑冒烟,不合理
    {
        try
        {
            comp.run();
            System.out.println("讲课");
        }
        catch (LanPingException e)
        {
                System.out.println(e.getMessage());
                comp.reset();                              //预处理,可以自己处理,所以才设置为编译时检测异常Exception,而不是运行时异常RuntimeException
                prelect();
        }
        catch (MaoYanException e)
        {
                System.out.println(e.getMessage());
                test();
                //可以对电脑进行维修,但是不传给调用者,因为他也处理不了
                //throw e;         //冒烟异常处理不了,返回给调用者在方法声明中标识出来。
                throw new prelectStop("课程进度无法完成!原因:" + e.getMessage());        //返回调用者可以处理的异常,异常进行了转换
        }



    }

    void test()
    {
        System.out.println("做练习");
    }
}


class ExceptionDemo6 
{
    public static void main(String[] args) 
    {
        Teacher t= new Teacher("毕老师");

        try
        {
            t.prelect();
        }
        catch (prelectStop e)
        {
                System.out.println(e.getMessage());
                System.out.println("换人");

        }

    }
}

10.异常的注意事项:
1.子类在覆盖父类方法时,父类方法如果抛出了异常,那么子类的方法只能抛出父类的异常或者该异常的子类,也可以不抛。
2.如果父类抛出多个异常,那么子类只能抛出父类异常的子集。

简单点说:如果父类的方法没有抛出异常,那么子类覆盖时绝对不能抛。(爸爸够坏了,儿子不能更坏了)

这时如果子类还是使用了异常,只能try,不能抛。
/*
原因:如果在方法2中传入了父类的对象,并trycatch了父类的方法1,这时catch中是父类的异常类型。如果有一个子类覆盖了父类的
方法1,这时如果方法2中传的是子类的对象(向上转型),则先调用的是子类中覆盖的方法,这时catch中的异常类型只有是父类的异常
或者子类才不会出现问题。
*/
//举例:
class A extends Exception
{
}

class B extends A
{
}

class C extends Exception
{
}


class Fu
{
    void show() throws A
        {}
}

class Zi extends Fu
{
    void show() throws B    //这时应该为A或者B
    {}
}

class Test
{
    void method(Fu f)
    {
            try
            {
                f.show();
            }
            catch(A a)     
            {
            }
    }
}

class ExceptionDemo7 
{
    public static void main(String[] args) 
    {
        Test t = new Test();
//      t.method(new Fu());
        t.method(new Zi());   
    }
}
发布了36 篇原创文章 · 获赞 0 · 访问量 4577
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章