java笔记--异常

2018-04-06  本文已影响0人  吃饱喝足搬代码丶

异常:

异常:是在运行时期发生的不正常现象。

在java中用类的形式对不正常情况进行了描述和封装对象。

描述不正常的情况的类,就称为异常类。

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

其实异常就是java通过面向对象的思想将问题封装成了对象。

用异常类对其进行描述。不同问题用不同的类进行具体的描述,比如角标越界,空指针等等。

异常体系:

最终问题(异常情况)就分成了两大类:Throwable(下面两种情况的父类):

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

无论error还是异常,都是问题,问题发生就应该可以抛出,让调用者知道并处理
该体系的特点在于Throwable及其所有的子类都具有可抛性。
可抛性到底指什么?怎么体现可抛性?
其实是通过两个关键字来体现--throws throw。凡是可以被这两个关键字所操作的类和对象都具备可抛性。

该体系的特点:
子类的后缀名都是用其父类名作为后缀,阅读性很强。

public class ExceptionDemo {
 
    public static void main(String[] args) {
        int[] arr=new int[1024*1024*800];//java.lang.OutOfMemoryError内存溢出
        sleep(-5);//但是时间没有负数,所以应该抛出异常
    } 
    public static void sleep(int time){
        //之前的处理方法是:if,阅读性差
/*      if(time<0){
            处理方法
            处理方法
            处理方法
        }
        if(time>1000000){
            处理方法
            处理方法
            处理方法
        }*/
        System.out.print("我睡。。。"+time);
    }
    public static void sleep2(int time){
        //现在的处理方法是:封装成类,调用异常类
//      if(time<0){
//          抛出 new FuTime();//就代码时间为负的情况,这个对象中会包含着问题的名称,信息,位置等信息。
//      }
//      if(time>1000000){
//          抛出 new BigTime();
//      }
        System.out.print("我睡。。。"+time);
    }
}

class FuTime{
}
class BigTime{
}

异常对象的抛出:

一般异常都是程序默认抛出异常,即由所调用的类抛出异常给(主函数里的)调用者,调用者抛给jvm,jvm直接显示异常的细节到Console。
但是,异常也可以由程序员抛出:

class Demo{
    public int method(int[] arr,int index){
        if(arr==null){
            throw new NullPointerException("数组的引用不能为空");
        }
        if(index>=arr.length){
            throw new ArrayIndexOutOfBoundsException("数组角标越界了"+index);
        }
        if(index<0){
            throw new ArrayIndexOutOfBoundsException("角标不能为负数"+index);
        }
        return arr[index];
    }
}
public class lizi {

    public static void main(String[] args) {
        int[] arr=new int[3];
        Demo d=new Demo();
        int num = d.method(null,8);
        //int num1= d.method(arr, 5);
        //int num2= d.method(arr, -4);
    }
}
运行:

自定义异常:

对于角标是整数不存在,可以用角标越界表示。
对于负数为角标的情况,准备用负数角标异常来表示。

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

这种自定义的问题描述称为自定义异常。

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

class FuShuIndexException extends Exception{
    FuShuIndexException(){
    }
    FuShuIndexException(String s){
        super(s);//原理看底下Person的例子
    }
}
class Demo{
    public int method(int[] arr,int index) throws FuShuIndexException{//声明抛出
        if(index<0){
            throw new FuShuIndexException("角标不能为负数"+index);
        }
        return arr[index];
    }
}
public class lizi {

    public static void main(String[] args) throws FuShuIndexException{//调用者也需声明抛出
        int[] arr=new int[3];
        Demo d=new Demo();
        int num2= d.method(arr, -4);
    }
}
/*
class Person{
    private String name;
    Person(String name){
        this.name=name;
    }
    public String getName(){
        return name;
    }
}
class Student extends Person{
    Student(String name){
        super(name);
    }
}
*/
运行:

Exception异常的分类:

1 编译时被检测异常:只要是Exception和其子类都是,除了特殊子类RuntimeException体系。 这种问题一旦出现,希望在编译时就进行检测,让这种问题有对应的处理方式。 这样的问题都可以针对性处理

声明的目的时让调用我们的调用者去处理问题

2 编译时不检测异常(运行时异常):就是Exception中的RuntimeException和其子类。这种问题的发生,无法让功能继续,运行无法进行,更多是因为调用的原因导致的,或者引发了内部状态的改变导致的。那么这种问题一般不处理,直接编译通过,在运行时,让调用者调用时的程序强制停止,让调用者对代码进行修正。
所以无需在throws子类句中进行声明(开发时比较常遇到)

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

throws和throw的区别:

1 throws使用在函数上;throw使用在函数内
2 throws抛出的是异常类,可以抛出多个,用“,”隔开;throw抛出的是异常对象。

class Demo{
    public int method(int[] arr,int index) 
    {
        if(arr==null){
            throw new NullPointerException("数组的引用不能为空");
        }
        if(index>=arr.length){
            throw new ArrayIndexOutOfBoundsException("数组角标越界了"+index);
        }
        return arr[index];
    }
}
public class lizi {

    public static void main(String[] args)
    {
        int[] arr=new int[3];
        Demo d=new Demo();
        int num = d.method(null,8);
    }
}

异常捕捉:

异常处理的捕捉形式:

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

具体格式是:
try{
//需要被检测异常的代码
}catch(异常类  变量){//该变量用于接收发生的异常对象
处理异常的代码
}finally{
//一定会被执行的代码
}

如果你内部能解决的问题就catch,如果解决不了就抛出去(try)让调用者处理

class FuShuIndexException extends Exception{
    FuShuIndexException(){
    }
    FuShuIndexException(String s){
        super(s);
    }
}

class Demo{
    public int method(int[] arr,int index) throws FuShuIndexException//声明抛出    
    {
        if(index<0){
            throw new FuShuIndexException("角标变成负数啦!!!");
        }
        return arr[index];
    }
}
class CatchDemo1{

    public static void main(String[] args)
    {
        int[] arr=new int[3];
        Demo d=new Demo();
        try{
            int num = d.method(arr,-8);
            System.out.print(num);
        }catch (FuShuIndexException x){
            System.out.println("message"+x.getMessage());
            System.out.println("String"+x);//本来应该输出的是哈希值,这里默认调用toString
            
            x.printStackTrace();//jvm默认的异常处理机制就是调用异常对象的这个方法
            System.out.println("负数角标异常!!!");
        }
        System.out.println("over");
    }
}
运行:
多catch情况:
class FuShuIndexException extends Exception{
    FuShuIndexException(){
    }
    FuShuIndexException(String s){
        super(s);
    }
}

class Demo{
    public int method(int[] arr,int index) throws FuShuIndexException//声明抛出    
    {
        if(arr==null){
            throw new NullPointerException("数组的引用不能为空");
        }
        if(index<0){
            throw new FuShuIndexException("角标变成负数啦!!!");
        }
        return arr[index];
    }
}
class CatchDemo1{

    public static void main(String[] args)
    {
        int[] arr=new int[3];
        Demo d=new Demo();
        try{
            int num = d.method(null,-8);
            System.out.print(num);
        }catch(NullPointerException y){
            System.out.println(y.toString());
        }
        catch (FuShuIndexException x){
            System.out.println("message"+x.getMessage());
            System.out.println("String"+x);//本来应该输出的是哈希值,这里默认调用toString
            
            x.printStackTrace();//jvm默认的异常处理机制就是调用异常对象的这个方法
            System.out.println("负数角标异常!!!");
        }/*catch(Exception e){//面试可能会有      除以上异常之外又有异常的情况下,就用这个catch,
                            //不管发生啥异常 全都接收,但必须放在最后一个catch之后
                            //一般情况下不会发生这种情况(除声明抛出异常的情况下,jvm还是报错的情况下)
                            //多catch下父类的catch放在最下面
        }*/
        System.out.println("over");
    }
}

异常处理的原则:

1 函数内部如果抛出需要检测的异常,那么函数上必须要声明(throws),否则必须在函数内用try-catch捕捉,否则编译失败。

2 如果调用到了声明异常的函数,要么trycatch要么throws,否则编译失败。

3 什么时候catch,什么时候throws呢?
内容功部可以解决,用catch;解决不了,用throws告诉调用者,由调用者解决。

4 一个功能如果抛出多个异常,那么调用时,必须对应多个catch进行针对性的处理。内部有几个需要检测的异常,就抛出几个异常,抛出几个,就catch几个。

finally:

class Demo{
    public int show(int index)throws ArrayIndexOutOfBoundsException//有了这个,主函数就得try了
    {
        if(index<0){
            throw new ArrayIndexOutOfBoundsException("数组角标越界了"+index);
        }
        int[] arr=new int[3];
        return arr[index];
    }
}
public class FinnallyDemo {

    public static void main(String[] args) {
        Demo d=new Demo();
        try{
            int num =d.show(-1);
            System.out.println(num);
        }
        catch(ArrayIndexOutOfBoundsException e){
            System.out.println(e.toString());
            //return ;//finally还是能执行到
            System.exit(0);//退出jvm,finally就执行不到了
        }finally{//开发的时候常用         通常用于关闭(释放)资源
            System.out.println("finally");
        }
        System.out.println("over");
    }

}
/*
连接数据库   数据库本身就有资源限制 所以浪费不得   所以一定要有finally
查询      可能过程中出问题了
关闭连接 -->但是这个无论怎样都要执行 所以定义在finally中

try catch finally 代码块组合特点:
1  try catch finally
2 try catch(多个)当没有必要资源需要释放时,可以不用定义finally。
3 try finally(常用)   异常无法直接catch处理,但是资源需要关闭。
void show() throws Exception{
    try{
        //开启资源
        throw new   Exception();//出现异常
        
    }
    finally{
        //关闭资源
    }
} 
*/

应用:

/*
 老师用电脑上课
 
 问题领域中涉及两个对象
 老师,电脑
 
 分析其中的问题:
 比如电脑蓝屏了。
*/
class LanPingException extends Exception{
    LanPingException(String msg){
        super(msg);
    }
}
class MaoYanException extends Exception{
    MaoYanException(String msg){
        super(msg);
    }
}
class NoWanChengException extends Exception{
    NoWanChengException(String msg){
        super(msg);
    }
}
class Computer{
    private int stats=2;//0,1,2
    public void run()throws LanPingException,MaoYanException
    {
        if(stats==1)
            throw new LanPingException("电脑蓝屏了");
        if(stats==2)
            throw new MaoYanException("电脑冒烟了");
        System.out.println("电脑运行");
    }
    public void reset(){
        stats=0;
        System.out.println("电脑重启");
    }
}
class Teacher{
    private String name;
    private Computer comp;
    Teacher(String name){
        this.name=name;
        comp=new Computer();
    }
    public void prelect ()throws NoWanChengException{
        try{
        comp.run();
        System.out.println("讲课");
        }catch(LanPingException e){
            System.out.println(e.toString());
            comp.reset();
            prelect();
        }catch(MaoYanException e){
            System.out.println(e.toString());
            test();
            //可以对电脑进行维修
//          throw e;并不是捕捉到异常就的抛出去,有的这边无法解决就得定义别的异常
                   //比如电脑冒烟,公司无法远程解决修理,就导致课程无法完成异常,所以就把问题换成解决无法完成课程的问题并抛出解决,老师可以换台电脑
            throw new NoWanChengException("课程无法完成"+e.getMessage());
        }
    }
    public void test(){
        System.out.println("大家练习");
    }
}
public class YingYong {

    public static void main(String[] args) {
        Teacher t=new Teacher("老师");
        try{
            t.prelect();
        }catch(NoWanChengException e){
            System.out.println(e.toString()+"...");
            System.out.println("老师换电脑");
        }   
    }
}
/*
class NoAddException extends Exception{}
void addData(Data d)throws (SQLException换成)NoAddException
{
    连接数据库
    try{
           添加数据,出现异常SQLException
    }catch(SQLException e){
        //处理代码                                 这种方式也叫做异常的封装,就是不该暴露的问题就没有必要暴露出去,即使暴露出去对方也没办法解决
        throw new NoAddException
    }finally{
     关闭数据库
    }
}
*/
运行:

异常注意事项:

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

2 如果父类抛出多个异常,那么子类只能抛出父类异常或者其子集。

简单说:子类覆盖父类只能抛出父类的异常或者子类或者子集。

注意:

如果父类没抛出异常,那么子类覆盖时绝对不能抛。就只能try。

上一篇下一篇

猜你喜欢

热点阅读